summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--.qmake.conf2
-rw-r--r--application-manager.pro9
-rw-r--r--benchmarks/appman-bench/am-config.yaml3
-rwxr-xr-xbenchmarks/appman-bench/run.sh5
-rw-r--r--benchmarks/appman-bench/system-ui/main.qml2
-rw-r--r--benchmarks/appman-bench/templates/appman-qml/main.qml2
-rw-r--r--benchmarks/appman-bench/templates/qmlscene/main.qml2
-rw-r--r--benchmarks/appman-bench/tests/controls2.qml2
-rw-r--r--benchmarks/appman-bench/tests/rect.qml2
-rw-r--r--benchmarks/appman-bench/tests/repeater.qml2
-rw-r--r--benchmarks/appman-bench/tests/shader.qml2
-rw-r--r--config.tests/libarchive/main.cpp2
-rw-r--r--config.tests/libyaml/main.cpp2
-rw-r--r--config.tests/touchemulation/main.cpp2
-rw-r--r--doc/QtApplicationManagerDoc1
-rw-r--r--doc/applicationmanager-project.qdocconf4
-rw-r--r--doc/config/exampleurl-qtapplicationmanager.qdocconf1
-rw-r--r--doc/configuration.qdoc121
-rw-r--r--doc/container.qdoc2
-rw-r--r--doc/controller.qdoc5
-rw-r--r--doc/debugging.qdoc2
-rw-r--r--doc/elements-apps.qdoc4
-rw-r--r--doc/elements-common.qdoc4
-rw-r--r--doc/elements-systemui.qdoc4
-rw-r--r--doc/index.qdoc3
-rw-r--r--doc/installation.qdoc11
-rw-r--r--doc/installer.qdoc2
-rw-r--r--doc/introduction.qdoc2
-rw-r--r--doc/manifest.qdoc9
-rw-r--r--doc/migration-guide-5.12.qdoc2
-rw-r--r--doc/package-format.qdoc2
-rw-r--r--doc/packager.qdoc2
-rw-r--r--doc/qmlmodule.qdoc2
-rw-r--r--doc/resources.qdoc140
-rw-r--r--doc/singlevsmultiprocess.qdoc2
-rw-r--r--doc/systemui.qdoc4
-rw-r--r--doc/troubleshooting.qdoc2
-rw-r--r--doc/write-applications.qdoc6
-rw-r--r--doc/yaml.qdoc2
-rw-r--r--examples/applicationmanager/animated-windows/animated-windows.pro2
-rw-r--r--examples/applicationmanager/animated-windows/apps/animated-windows.fish/fish.qml2
-rw-r--r--examples/applicationmanager/animated-windows/apps/animated-windows.rabbit/rabbit.qml2
-rw-r--r--examples/applicationmanager/animated-windows/doc/src/animated-windows.qdoc2
-rw-r--r--examples/applicationmanager/animated-windows/system-ui/main.qml2
-rw-r--r--examples/applicationmanager/application-features/am-config.yaml24
-rw-r--r--examples/applicationmanager/application-features/application-features.pro4
-rw-r--r--examples/applicationmanager/application-features/application-features.qmlproject17
-rw-r--r--examples/applicationmanager/application-features/apps/compositor/compositor.qml107
-rw-r--r--examples/applicationmanager/application-features/apps/compositor/icon.pngbin0 -> 5337 bytes
-rw-r--r--examples/applicationmanager/application-features/apps/compositor/info.yaml9
-rw-r--r--examples/applicationmanager/application-features/apps/crash/crashapp.qml101
-rw-r--r--examples/applicationmanager/application-features/apps/crash/icon.pngbin0 -> 3689 bytes
-rw-r--r--examples/applicationmanager/application-features/apps/crash/info.yaml11
-rw-r--r--examples/applicationmanager/application-features/apps/twins/icon.pngbin0 -> 776 bytes
-rw-r--r--examples/applicationmanager/application-features/apps/twins/info.yaml9
-rw-r--r--examples/applicationmanager/application-features/apps/twins/twins.qml104
-rw-r--r--examples/applicationmanager/application-features/apps/widgets/icon.pngbin0 -> 2167 bytes
-rw-r--r--examples/applicationmanager/application-features/apps/widgets/info.yaml13
-rw-r--r--examples/applicationmanager/application-features/client.qml77
-rw-r--r--examples/applicationmanager/application-features/doc/images/application-features.pngbin0 -> 43713 bytes
-rw-r--r--examples/applicationmanager/application-features/doc/src/application-features.qdoc134
-rw-r--r--examples/applicationmanager/application-features/imports/imports.pro2
-rw-r--r--examples/applicationmanager/application-features/imports/terminator2/qmldir2
-rw-r--r--examples/applicationmanager/application-features/imports/terminator2/qmlterminator2.cpp106
-rw-r--r--examples/applicationmanager/application-features/imports/terminator2/qmlterminator2.h74
-rw-r--r--examples/applicationmanager/application-features/imports/terminator2/terminator2.pro21
-rw-r--r--examples/applicationmanager/application-features/native/native.pro4
-rw-r--r--examples/applicationmanager/application-features/native/widgets/main.cpp90
-rw-r--r--examples/applicationmanager/application-features/native/widgets/widgets.pro10
-rw-r--r--examples/applicationmanager/application-features/system-ui/grab.pngbin0 -> 357 bytes
-rw-r--r--examples/applicationmanager/application-features/system-ui/main.qml216
-rw-r--r--examples/applicationmanager/application-features/ui.pro36
-rw-r--r--examples/applicationmanager/applicationmanager.pro1
-rw-r--r--examples/applicationmanager/custom-appman/custom-appman.cpp13
-rw-r--r--examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc4
-rw-r--r--examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.qml2
-rw-r--r--examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.qml2
-rw-r--r--examples/applicationmanager/frame-timer/doc/src/frame-timer-example.qdoc2
-rw-r--r--examples/applicationmanager/frame-timer/frame-timer.pro2
-rw-r--r--examples/applicationmanager/frame-timer/system-ui/main.qml2
-rw-r--r--examples/applicationmanager/hello-world/apps/hello-world.blue/main.qml2
-rw-r--r--examples/applicationmanager/hello-world/apps/hello-world.green/main.qml2
-rw-r--r--examples/applicationmanager/hello-world/apps/hello-world.red/main.qml2
-rw-r--r--examples/applicationmanager/hello-world/doc/src/hello-world.qdoc4
-rw-r--r--examples/applicationmanager/hello-world/system-ui.qml2
-rw-r--r--examples/applicationmanager/intents/apps/intents.blue/main.qml2
-rw-r--r--examples/applicationmanager/intents/apps/intents.green/main.qml2
-rw-r--r--examples/applicationmanager/intents/apps/intents.red/main.qml2
-rw-r--r--examples/applicationmanager/intents/doc/src/intents.qdoc2
-rw-r--r--examples/applicationmanager/intents/shared/IntentsApplicationWindow.qml2
-rw-r--r--examples/applicationmanager/intents/shared/IntentsUIPage.qml2
-rw-r--r--examples/applicationmanager/intents/system-ui.qml7
-rw-r--r--examples/applicationmanager/minidesk/am-config.yaml10
-rw-r--r--examples/applicationmanager/minidesk/apps/tld.minidesk.app1/app1.qml8
-rw-r--r--examples/applicationmanager/minidesk/apps/tld.minidesk.app1/icon.pngbin5138 -> 4804 bytes
-rw-r--r--examples/applicationmanager/minidesk/apps/tld.minidesk.app1/info.yaml12
-rw-r--r--examples/applicationmanager/minidesk/apps/tld.minidesk.app2/app2.qml4
-rw-r--r--examples/applicationmanager/minidesk/apps/tld.minidesk.app2/icon.pngbin5597 -> 4399 bytes
-rw-r--r--examples/applicationmanager/minidesk/apps/tld.minidesk.app2/info.yaml12
-rw-r--r--examples/applicationmanager/minidesk/doc/images/minidesk.pngbin103040 -> 84974 bytes
-rw-r--r--examples/applicationmanager/minidesk/doc/src/minidesk.qdoc23
-rw-r--r--examples/applicationmanager/minidesk/system-ui/Readme.qml2
-rw-r--r--examples/applicationmanager/minidesk/system-ui/chrome-bg.pngbin0 -> 488 bytes
-rw-r--r--examples/applicationmanager/minidesk/system-ui/main.qml15
-rw-r--r--examples/applicationmanager/multi-views/apps/tld.multi-views.app/app1.qml2
-rw-r--r--examples/applicationmanager/multi-views/doc/src/multi-views.qdoc2
-rw-r--r--examples/applicationmanager/multi-views/multi-views.pro4
-rw-r--r--examples/applicationmanager/multi-views/system-ui/Readme.qml2
-rw-r--r--examples/applicationmanager/multi-views/system-ui/main.qml2
-rw-r--r--examples/applicationmanager/process-status/apps/process-status.cpu-hog/main.qml2
-rw-r--r--examples/applicationmanager/process-status/apps/process-status.mem-hog/main.qml2
-rw-r--r--examples/applicationmanager/process-status/apps/process-status.slim/main.qml2
-rw-r--r--examples/applicationmanager/process-status/doc/src/process-status-example.qdoc2
-rw-r--r--examples/applicationmanager/process-status/process-status.pro2
-rw-r--r--examples/applicationmanager/process-status/system-ui/ApplicationDisplay.qml2
-rw-r--r--examples/applicationmanager/process-status/system-ui/CpuGraph.qml2
-rw-r--r--examples/applicationmanager/process-status/system-ui/MemoryText.qml2
-rw-r--r--examples/applicationmanager/process-status/system-ui/Stats.qml2
-rw-r--r--examples/applicationmanager/process-status/system-ui/main.qml2
-rw-r--r--examples/applicationmanager/softwarecontainer-plugin/doc/src/softwarecontainer-plugin.qdoc2
-rw-r--r--examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.cpp2
-rw-r--r--examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.h2
-rw-r--r--examples/applicationmanager/startup-plugin/startup-plugin.cpp2
-rw-r--r--examples/applicationmanager/startup-plugin/startup-plugin.h2
-rw-r--r--header.BSD-QTAS3
-rw-r--r--header.FDL-QTAS3
-rw-r--r--header.GPL-EXCEPT-QTAS3
-rw-r--r--header.LGPL-QTAS3
-rw-r--r--qmake-features/am-qml-testcase.prf16
-rw-r--r--qmake-features/generate-resource.prf10
-rw-r--r--src/application-lib/application-lib.pro12
-rw-r--r--src/application-lib/applicationinfo.cpp355
-rw-r--r--src/application-lib/applicationinfo.h115
-rw-r--r--src/application-lib/applicationinterface.cpp2
-rw-r--r--src/application-lib/applicationinterface.h2
-rw-r--r--src/application-lib/installationreport.cpp114
-rw-r--r--src/application-lib/installationreport.h17
-rw-r--r--src/application-lib/intentinfo.cpp147
-rw-r--r--src/application-lib/intentinfo.h105
-rw-r--r--src/application-lib/packagedatabase.cpp257
-rw-r--r--src/application-lib/packagedatabase.h (renamed from src/installer-lib/installationlocation.h)59
-rw-r--r--src/application-lib/packageinfo.cpp314
-rw-r--r--src/application-lib/packageinfo.h131
-rw-r--r--src/application-lib/packagescanner.h (renamed from src/application-lib/applicationscanner.h)22
-rw-r--r--src/application-lib/yamlapplicationscanner.cpp229
-rw-r--r--src/application-lib/yamlapplicationscanner.h67
-rw-r--r--src/application-lib/yamlpackagescanner.cpp359
-rw-r--r--src/application-lib/yamlpackagescanner.h61
-rw-r--r--src/common-lib/common-lib.pro5
-rw-r--r--src/common-lib/configcache.cpp414
-rw-r--r--src/common-lib/configcache.h158
-rw-r--r--src/common-lib/configcache_p.h (renamed from src/manager-lib/applicationdatabase.h)56
-rw-r--r--src/common-lib/crashhandler.cpp2
-rw-r--r--src/common-lib/crashhandler.h2
-rw-r--r--src/common-lib/dbus-utilities.cpp2
-rw-r--r--src/common-lib/dbus-utilities.h2
-rw-r--r--src/common-lib/error.h2
-rw-r--r--src/common-lib/exception.cpp2
-rw-r--r--src/common-lib/exception.h24
-rw-r--r--src/common-lib/global.h2
-rw-r--r--src/common-lib/logging.cpp23
-rw-r--r--src/common-lib/logging.h5
-rw-r--r--src/common-lib/processtitle.cpp2
-rw-r--r--src/common-lib/processtitle.h2
-rw-r--r--src/common-lib/qml-utilities.cpp2
-rw-r--r--src/common-lib/qml-utilities.h2
-rw-r--r--src/common-lib/qtyaml.cpp746
-rw-r--r--src/common-lib/qtyaml.h84
-rw-r--r--src/common-lib/startuptimer.cpp27
-rw-r--r--src/common-lib/startuptimer.h2
-rw-r--r--src/common-lib/unixsignalhandler.cpp2
-rw-r--r--src/common-lib/unixsignalhandler.h2
-rw-r--r--src/common-lib/utilities.cpp65
-rw-r--r--src/common-lib/utilities.h45
-rw-r--r--src/crypto-lib/cryptography.cpp2
-rw-r--r--src/crypto-lib/cryptography.h2
-rw-r--r--src/crypto-lib/libcryptofunction.cpp2
-rw-r--r--src/crypto-lib/libcryptofunction.h2
-rw-r--r--src/crypto-lib/signature.cpp2
-rw-r--r--src/crypto-lib/signature.h2
-rw-r--r--src/crypto-lib/signature_macos.cpp2
-rw-r--r--src/crypto-lib/signature_openssl.cpp2
-rw-r--r--src/crypto-lib/signature_p.h2
-rw-r--r--src/crypto-lib/signature_win.cpp2
-rw-r--r--src/dbus-lib/abstractdbuscontextadaptor.cpp2
-rw-r--r--src/dbus-lib/abstractdbuscontextadaptor.h2
-rw-r--r--src/dbus-lib/applicationinstallerdbuscontextadaptor.cpp204
-rw-r--r--src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp2
-rw-r--r--src/dbus-lib/applicationmanagerdbuscontextadaptor.h2
-rw-r--r--src/dbus-lib/dbus-lib.pro15
-rw-r--r--src/dbus-lib/dbusdaemon.cpp2
-rw-r--r--src/dbus-lib/dbusdaemon.h2
-rw-r--r--src/dbus-lib/dbuspolicy.cpp2
-rw-r--r--src/dbus-lib/dbuspolicy.h2
-rw-r--r--src/dbus-lib/io.qt.packagemanager.xml (renamed from src/dbus-lib/io.qt.applicationinstaller.xml)29
-rw-r--r--src/dbus-lib/notificationmanagerdbuscontextadaptor.cpp2
-rw-r--r--src/dbus-lib/notificationmanagerdbuscontextadaptor.h2
-rw-r--r--src/dbus-lib/packagemanagerdbuscontextadaptor.cpp210
-rw-r--r--src/dbus-lib/packagemanagerdbuscontextadaptor.h (renamed from src/dbus-lib/applicationinstallerdbuscontextadaptor.h)8
-rw-r--r--src/dbus-lib/windowmanagerdbuscontextadaptor.cpp2
-rw-r--r--src/dbus-lib/windowmanagerdbuscontextadaptor.h2
-rw-r--r--src/installer-lib/applicationinstaller.cpp1042
-rw-r--r--src/installer-lib/installationlocation.cpp229
-rw-r--r--src/installer-lib/installer-lib.pro40
-rw-r--r--src/intent-client-lib/intentclient.cpp5
-rw-r--r--src/intent-client-lib/intentclient.h8
-rw-r--r--src/intent-client-lib/intentclientrequest.cpp17
-rw-r--r--src/intent-client-lib/intentclientrequest.h2
-rw-r--r--src/intent-client-lib/intentclientsysteminterface.cpp2
-rw-r--r--src/intent-client-lib/intentclientsysteminterface.h2
-rw-r--r--src/intent-client-lib/intenthandler.cpp5
-rw-r--r--src/intent-client-lib/intenthandler.h2
-rw-r--r--src/intent-server-lib/intent-server-lib.pro6
-rw-r--r--src/intent-server-lib/intent.cpp138
-rw-r--r--src/intent-server-lib/intent.h53
-rw-r--r--src/intent-server-lib/intentmodel.cpp285
-rw-r--r--src/intent-server-lib/intentmodel.h100
-rw-r--r--src/intent-server-lib/intentserver.cpp446
-rw-r--r--src/intent-server-lib/intentserver.h99
-rw-r--r--src/intent-server-lib/intentserverrequest.cpp9
-rw-r--r--src/intent-server-lib/intentserverrequest.h9
-rw-r--r--src/intent-server-lib/intentserversysteminterface.cpp8
-rw-r--r--src/intent-server-lib/intentserversysteminterface.h2
-rw-r--r--src/launcher-lib/applicationmanagerwindow.cpp2
-rw-r--r--src/launcher-lib/applicationmanagerwindow_p.h2
-rw-r--r--src/launcher-lib/dbusapplicationinterface.cpp (renamed from src/launcher-lib/qmlapplicationinterface.cpp)94
-rw-r--r--src/launcher-lib/dbusapplicationinterface.h (renamed from src/launcher-lib/qmlapplicationinterface.h)24
-rw-r--r--src/launcher-lib/dbusapplicationinterfaceextension.cpp (renamed from src/launcher-lib/qmlapplicationinterfaceextension.cpp)40
-rw-r--r--src/launcher-lib/dbusapplicationinterfaceextension.h (renamed from src/launcher-lib/qmlapplicationinterfaceextension.h)12
-rw-r--r--src/launcher-lib/dbusnotification.cpp (renamed from src/launcher-lib/qmlnotification.cpp)25
-rw-r--r--src/launcher-lib/dbusnotification.h (renamed from src/launcher-lib/qmlnotification.h)12
-rw-r--r--src/launcher-lib/intentclientdbusimplementation.cpp2
-rw-r--r--src/launcher-lib/intentclientdbusimplementation.h2
-rw-r--r--src/launcher-lib/ipcwrapperobject.cpp2
-rw-r--r--src/launcher-lib/ipcwrapperobject.h2
-rw-r--r--src/launcher-lib/ipcwrapperobject_p.h2
-rw-r--r--src/launcher-lib/launcher-lib.pro12
-rw-r--r--src/launcher-lib/launchermain.cpp34
-rw-r--r--src/launcher-lib/launchermain.h24
-rw-r--r--src/launcher-lib/waylandqtamclientextension.cpp2
-rw-r--r--src/launcher-lib/waylandqtamclientextension_p.h4
-rw-r--r--src/main-lib/applicationinstaller.cpp477
-rw-r--r--src/main-lib/applicationinstaller.h (renamed from src/installer-lib/applicationinstaller.h)165
-rw-r--r--src/main-lib/configuration.cpp1252
-rw-r--r--src/main-lib/configuration.h105
-rw-r--r--src/main-lib/configuration_p.h171
-rw-r--r--src/main-lib/defaultconfiguration.cpp503
-rw-r--r--src/main-lib/defaultconfiguration.h90
-rw-r--r--src/main-lib/main-lib.pro4
-rw-r--r--src/main-lib/main.cpp407
-rw-r--r--src/main-lib/main.h42
-rw-r--r--src/main-lib/windowframetimer.cpp2
-rw-r--r--src/main-lib/windowframetimer.h2
-rw-r--r--src/manager-lib/abstractcontainer.cpp8
-rw-r--r--src/manager-lib/abstractcontainer.h16
-rw-r--r--src/manager-lib/abstractruntime.cpp2
-rw-r--r--src/manager-lib/abstractruntime.h2
-rw-r--r--src/manager-lib/amnamespace.h2
-rw-r--r--src/manager-lib/application.cpp392
-rw-r--r--src/manager-lib/application.h198
-rw-r--r--src/manager-lib/applicationdatabase.cpp184
-rw-r--r--src/manager-lib/applicationipcinterface.cpp10
-rw-r--r--src/manager-lib/applicationipcinterface.h8
-rw-r--r--src/manager-lib/applicationipcinterface_p.h8
-rw-r--r--src/manager-lib/applicationipcmanager.cpp2
-rw-r--r--src/manager-lib/applicationipcmanager.h2
-rw-r--r--src/manager-lib/applicationmanager.cpp484
-rw-r--r--src/manager-lib/applicationmanager.h55
-rw-r--r--src/manager-lib/applicationmanager_p.h5
-rw-r--r--src/manager-lib/applicationmodel.cpp44
-rw-r--r--src/manager-lib/applicationmodel.h7
-rw-r--r--src/manager-lib/asynchronoustask.cpp (renamed from src/installer-lib/asynchronoustask.cpp)16
-rw-r--r--src/manager-lib/asynchronoustask.h (renamed from src/installer-lib/asynchronoustask.h)10
-rw-r--r--src/manager-lib/containerfactory.cpp4
-rw-r--r--src/manager-lib/containerfactory.h6
-rw-r--r--src/manager-lib/debugwrapper.cpp2
-rw-r--r--src/manager-lib/debugwrapper.h2
-rw-r--r--src/manager-lib/deinstallationtask.cpp (renamed from src/installer-lib/deinstallationtask.cpp)90
-rw-r--r--src/manager-lib/deinstallationtask.h (renamed from src/installer-lib/deinstallationtask.h)13
-rw-r--r--src/manager-lib/inprocesssurfaceitem.cpp2
-rw-r--r--src/manager-lib/inprocesssurfaceitem.h2
-rw-r--r--src/manager-lib/installationtask.cpp (renamed from src/installer-lib/installationtask.cpp)186
-rw-r--r--src/manager-lib/installationtask.h (renamed from src/installer-lib/installationtask.h)23
-rw-r--r--src/manager-lib/intentaminterface.cpp149
-rw-r--r--src/manager-lib/intentaminterface.h12
-rw-r--r--src/manager-lib/manager-lib.pro29
-rw-r--r--src/manager-lib/nativeruntime.cpp35
-rw-r--r--src/manager-lib/nativeruntime.h4
-rw-r--r--src/manager-lib/nativeruntime_p.h2
-rw-r--r--src/manager-lib/notificationmanager.cpp10
-rw-r--r--src/manager-lib/notificationmanager.h2
-rw-r--r--src/manager-lib/package.cpp247
-rw-r--r--src/manager-lib/package.h149
-rw-r--r--src/manager-lib/packagemanager.cpp1321
-rw-r--r--src/manager-lib/packagemanager.h235
-rw-r--r--src/manager-lib/packagemanager_p.h (renamed from src/installer-lib/applicationinstaller_p.h)20
-rw-r--r--src/manager-lib/plugincontainer.cpp6
-rw-r--r--src/manager-lib/plugincontainer.h6
-rw-r--r--src/manager-lib/processcontainer.cpp6
-rw-r--r--src/manager-lib/processcontainer.h6
-rw-r--r--src/manager-lib/processstatus.cpp4
-rw-r--r--src/manager-lib/processstatus.h4
-rw-r--r--src/manager-lib/qmlinprocessapplicationinterface.cpp6
-rw-r--r--src/manager-lib/qmlinprocessapplicationinterface.h2
-rw-r--r--src/manager-lib/qmlinprocessapplicationmanagerwindow.cpp4
-rw-r--r--src/manager-lib/qmlinprocessapplicationmanagerwindow.h2
-rw-r--r--src/manager-lib/qmlinprocessruntime.cpp35
-rw-r--r--src/manager-lib/qmlinprocessruntime.h3
-rw-r--r--src/manager-lib/quicklauncher.cpp2
-rw-r--r--src/manager-lib/quicklauncher.h2
-rw-r--r--src/manager-lib/runtimefactory.cpp2
-rw-r--r--src/manager-lib/runtimefactory.h2
-rw-r--r--src/manager-lib/scopeutilities.cpp (renamed from src/installer-lib/scopeutilities.cpp)5
-rw-r--r--src/manager-lib/scopeutilities.h (renamed from src/installer-lib/scopeutilities.h)2
-rw-r--r--src/manager-lib/sudo.cpp (renamed from src/installer-lib/sudo.cpp)2
-rw-r--r--src/manager-lib/sudo.h (renamed from src/installer-lib/sudo.h)2
-rw-r--r--src/monitor-lib/processreader.cpp5
-rw-r--r--src/monitor-lib/processreader.h2
-rw-r--r--src/monitor-lib/sysfsreader.cpp11
-rw-r--r--src/monitor-lib/sysfsreader.h2
-rw-r--r--src/monitor-lib/systemreader.cpp16
-rw-r--r--src/monitor-lib/systemreader.h2
-rw-r--r--src/notification-lib/notification.cpp2
-rw-r--r--src/notification-lib/notification.h2
-rw-r--r--src/package-lib/package-lib.pro7
-rw-r--r--src/package-lib/package_p.cpp90
-rw-r--r--src/package-lib/packagecreator.cpp14
-rw-r--r--src/package-lib/packagecreator.h2
-rw-r--r--src/package-lib/packagecreator_p.h2
-rw-r--r--src/package-lib/packageextractor.cpp31
-rw-r--r--src/package-lib/packageextractor.h2
-rw-r--r--src/package-lib/packageextractor_p.h2
-rw-r--r--src/package-lib/packageutilities.cpp (renamed from src/package-lib/package.cpp)53
-rw-r--r--src/package-lib/packageutilities.h (renamed from src/package-lib/package.h)4
-rw-r--r--src/package-lib/packageutilities_p.h (renamed from src/package-lib/package_p.h)13
-rw-r--r--src/plugin-interfaces/containerinterface.cpp6
-rw-r--r--src/plugin-interfaces/containerinterface.h2
-rw-r--r--src/plugin-interfaces/startupinterface.cpp2
-rw-r--r--src/plugin-interfaces/startupinterface.h2
-rw-r--r--src/shared-main-lib/cpustatus.cpp2
-rw-r--r--src/shared-main-lib/cpustatus.h2
-rw-r--r--src/shared-main-lib/frametimer.cpp2
-rw-r--r--src/shared-main-lib/frametimer.h2
-rw-r--r--src/shared-main-lib/gpustatus.cpp2
-rw-r--r--src/shared-main-lib/gpustatus.h2
-rw-r--r--src/shared-main-lib/iostatus.cpp2
-rw-r--r--src/shared-main-lib/iostatus.h2
-rw-r--r--src/shared-main-lib/memorystatus.cpp2
-rw-r--r--src/shared-main-lib/memorystatus.h2
-rw-r--r--src/shared-main-lib/monitormodel.cpp2
-rw-r--r--src/shared-main-lib/monitormodel.h2
-rw-r--r--src/shared-main-lib/qmllogger.cpp2
-rw-r--r--src/shared-main-lib/qmllogger.h2
-rw-r--r--src/shared-main-lib/sharedmain.cpp43
-rw-r--r--src/shared-main-lib/sharedmain.h5
-rw-r--r--src/src.pro25
-rw-r--r--src/tools/appman/appman.cpp21
-rw-r--r--src/tools/appman/appman.pro8
-rw-r--r--src/tools/controller/controller.cpp164
-rw-r--r--src/tools/controller/controller.pro2
-rw-r--r--src/tools/controller/interrupthandler.cpp2
-rw-r--r--src/tools/controller/interrupthandler.h2
-rw-r--r--src/tools/dumpqmltypes/dumpqmltypes.cpp23
-rw-r--r--src/tools/dumpqmltypes/dumpqmltypes.pro2
-rw-r--r--src/tools/launcher-qml/launcher-qml.cpp176
-rw-r--r--src/tools/launcher-qml/launcher-qml_p.h10
-rw-r--r--src/tools/packager/packager.cpp34
-rw-r--r--src/tools/packager/packagingjob.cpp55
-rw-r--r--src/tools/packager/packagingjob.h2
-rw-r--r--src/tools/testrunner/testrunner.cpp17
-rw-r--r--src/tools/testrunner/testrunner.h4
-rw-r--r--src/tools/testrunner/testrunner_p.h2
-rw-r--r--src/tools/uploader/uploader.cpp6
-rw-r--r--src/wayland-extensions/qtam-extension.xml2
-rw-r--r--src/window-lib/inprocesswindow.cpp4
-rw-r--r--src/window-lib/inprocesswindow.h4
-rw-r--r--src/window-lib/touchemulation.cpp2
-rw-r--r--src/window-lib/touchemulation.h2
-rw-r--r--src/window-lib/touchemulation_x11.cpp2
-rw-r--r--src/window-lib/touchemulation_x11_p.h2
-rw-r--r--src/window-lib/waylandcompositor.cpp42
-rw-r--r--src/window-lib/waylandcompositor.h31
-rw-r--r--src/window-lib/waylandqtamserverextension.cpp2
-rw-r--r--src/window-lib/waylandqtamserverextension_p.h2
-rw-r--r--src/window-lib/waylandwindow.cpp6
-rw-r--r--src/window-lib/waylandwindow.h5
-rw-r--r--src/window-lib/window-lib.pro2
-rw-r--r--src/window-lib/window.cpp6
-rw-r--r--src/window-lib/window.h10
-rw-r--r--src/window-lib/windowitem.cpp2
-rw-r--r--src/window-lib/windowitem.h2
-rw-r--r--src/window-lib/windowmanager.cpp58
-rw-r--r--src/window-lib/windowmanager.h9
-rw-r--r--src/window-lib/windowmanager_p.h4
-rw-r--r--sync.profile1
-rw-r--r--template-opt/am/config-windows.yaml14
-rw-r--r--template-opt/am/config.yaml19
-rw-r--r--tests/application/application.pro3
-rw-r--r--tests/application/icon.pngbin0 -> 68 bytes
-rw-r--r--tests/application/info.yaml10
-rw-r--r--tests/application/tst_application.cpp16
-rw-r--r--tests/application/tst_application.qrc5
-rw-r--r--tests/applicationinfo/tst_applicationinfo.cpp194
-rw-r--r--tests/applicationinstaller/applicationinstaller.pro1
-rw-r--r--tests/applicationinstaller/tst_applicationinstaller.cpp410
-rw-r--r--tests/cryptography/tst_cryptography.cpp2
-rwxr-xr-xtests/data/certificates/create-test-certificates.sh2
-rwxr-xr-xtests/data/create-test-packages.sh12
-rw-r--r--tests/data/hello-world.red/info.yaml1
-rw-r--r--tests/data/manifests/com.pelagicore.test/info.yaml2
-rwxr-xr-xtests/data/utilities.sh2
-rw-r--r--tests/debugwrapper/tst_debugwrapper.cpp2
-rw-r--r--tests/error-checking.h4
-rw-r--r--tests/installationreport/tst_installationreport.cpp23
-rw-r--r--tests/main/am-config.yaml12
-rw-r--r--tests/main/builtin-apps/hello-world.red/info.yaml21
-rw-r--r--tests/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml (renamed from tests/main/dir-with-update-already-installed/manifests/hello-world.red/installation-report.yaml)7
-rw-r--r--tests/main/dummy.qml0
-rw-r--r--tests/main/main.pro6
-rw-r--r--tests/main/main.qrc5
-rw-r--r--tests/main/tst_main.cpp164
-rw-r--r--tests/manual/manual.pro6
-rw-r--r--tests/manual/monitormodel/PropertyField.qml2
-rw-r--r--tests/manual/monitormodel/SystemMonitorChart.qml2
-rw-r--r--tests/manual/monitormodel/main.qml4
-rw-r--r--tests/manual/monitormodel/monitormodel.pro5
-rw-r--r--tests/packagecreator/tst_packagecreator.cpp8
-rw-r--r--tests/packageextractor/tst_packageextractor.cpp8
-rw-r--r--tests/packager-tool/packager-tool.pro5
-rw-r--r--tests/packager-tool/tst_packager-tool.cpp80
-rw-r--r--tests/processreader/tst_processreader.cpp2
-rw-r--r--tests/qml/configs/am-config.yaml10
-rw-r--r--tests/qml/configs/apps/test.configs.app/app.qml2
-rw-r--r--tests/qml/configs/configs.pro1
-rw-r--r--tests/qml/configs/tst_configs.qml4
-rw-r--r--tests/qml/crash/am-config.yaml9
-rw-r--r--tests/qml/crash/apps/tld.test.crash/app.qml2
-rw-r--r--tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp2
-rw-r--r--tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h2
-rw-r--r--tests/qml/crash/crash.pro2
-rw-r--r--tests/qml/crash/tst_crash.qml2
-rw-r--r--tests/qml/installer/am-config.yaml12
-rw-r--r--tests/qml/installer/apps/hello-world.red/app1.qml (renamed from tests/qml/installer/apps/builtin.app/app1.qml)2
-rw-r--r--tests/qml/installer/apps/hello-world.red/icon1.png (renamed from tests/qml/installer/apps/builtin.app/icon1.png)bin1486 -> 1486 bytes
-rw-r--r--tests/qml/installer/apps/hello-world.red/info.yaml (renamed from tests/qml/installer/apps/builtin.app/info.yaml)2
-rw-r--r--tests/qml/installer/appv1.pkgbin10240 -> 0 bytes
-rw-r--r--tests/qml/installer/appv2.pkgbin10240 -> 0 bytes
-rw-r--r--tests/qml/installer/builtinv2.pkgbin10240 -> 0 bytes
-rw-r--r--tests/qml/installer/install-apps/appv1/info.yaml10
-rw-r--r--tests/qml/installer/install-apps/appv2/info.yaml10
-rw-r--r--tests/qml/installer/install-apps/builtinv2/icon2.pngbin1486 -> 0 bytes
-rw-r--r--tests/qml/installer/install-apps/builtinv2/info.yaml10
-rw-r--r--tests/qml/installer/installer.pro2
-rw-r--r--tests/qml/installer/tst_installer.qml169
-rw-r--r--tests/qml/intents/am-config.yaml2
-rw-r--r--tests/qml/intents/apps/intents1/intents1.qml2
-rw-r--r--tests/qml/intents/apps/intents2/intents2.qml2
-rw-r--r--tests/qml/intents/intents.pro4
-rw-r--r--tests/qml/intents/tst_intents.qml63
-rw-r--r--tests/qml/lifecycle/am-config.yaml9
-rw-r--r--tests/qml/qml.pro3
-rw-r--r--tests/qml/quicklaunch/am-config.yaml10
-rw-r--r--tests/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml2
-rw-r--r--tests/qml/quicklaunch/quicklaunch.pro1
-rw-r--r--tests/qml/quicklaunch/tst_quicklaunch.qml2
-rw-r--r--tests/qml/resources/am-config.yaml22
-rw-r--r--tests/qml/resources/appcommon/Quicklaunch.qml47
-rw-r--r--tests/qml/resources/appcommon/appcommon.pro7
-rw-r--r--tests/qml/resources/appcommon/appcommonfile.qrc7
-rw-r--r--tests/qml/resources/appcommon/qml/common/CommonObj.qml46
-rw-r--r--tests/qml/resources/appcommon/qml/common/qmldir2
-rw-r--r--tests/qml/resources/apps/app1/app1.pro11
-rw-r--r--tests/qml/resources/apps/app1/app1.qml48
-rw-r--r--tests/qml/resources/apps/app1/app1file.qrc7
-rw-r--r--tests/qml/resources/apps/app1/app1plugin.qrc5
-rw-r--r--tests/qml/resources/apps/app1/icon.png (renamed from tests/qml/installer/install-apps/appv1/icon1.png)bin1486 -> 1486 bytes
-rw-r--r--tests/qml/resources/apps/app1/info.yaml17
-rw-r--r--tests/qml/resources/apps/app1/qml/forms/AquaRect.qml (renamed from tests/qml/installer/install-apps/appv2/app2.qml)8
-rw-r--r--tests/qml/resources/apps/app1/qml/forms/YellowRect.qml46
-rw-r--r--tests/qml/resources/apps/app1/qml/forms/qmldir4
-rw-r--r--tests/qml/resources/apps/app2/BlueRect.qml (renamed from tests/qml/installer/install-apps/appv1/app1.qml)8
-rw-r--r--tests/qml/resources/apps/app2/app2.pro8
-rw-r--r--tests/qml/resources/apps/app2/app2.qml57
-rw-r--r--tests/qml/resources/apps/app2/app2.qrc6
-rw-r--r--tests/qml/resources/apps/app2/icon.png (renamed from tests/qml/installer/install-apps/appv2/icon2.png)bin1486 -> 1486 bytes
-rw-r--r--tests/qml/resources/apps/app2/info.yaml15
-rw-r--r--tests/qml/resources/apps/app2/qml/appwidgets/GreenRect.qml46
-rw-r--r--tests/qml/resources/apps/app2/qml/appwidgets/qmldir2
-rw-r--r--tests/qml/resources/qml/widgets/MagentaRect.qml46
-rw-r--r--tests/qml/resources/qml/widgets/RedRect.qml (renamed from tests/qml/installer/install-apps/builtinv2/app2.qml)4
-rw-r--r--tests/qml/resources/qml/widgets/qmldir3
-rw-r--r--tests/qml/resources/resources.pro5
-rw-r--r--tests/qml/resources/systemuifile.qrc6
-rw-r--r--tests/qml/resources/systemuiplugin.qrc5
-rw-r--r--tests/qml/resources/test.pro18
-rw-r--r--tests/qml/resources/tst_resource.qml92
-rw-r--r--tests/qml/simple/am-config.yaml10
-rw-r--r--tests/qml/simple/apps/tld.test.simple1/app1.qml2
-rw-r--r--tests/qml/simple/apps/tld.test.simple1/info-alias.yaml9
-rw-r--r--tests/qml/simple/apps/tld.test.simple2/app.qml2
-rw-r--r--tests/qml/simple/simple.pro1
-rw-r--r--tests/qml/simple/tst_applicationmanager.qml75
-rw-r--r--tests/qml/windowitem/am-config.yaml12
-rw-r--r--tests/qml/windowitem/apps/test.windowitem.app/main.qml2
-rw-r--r--tests/qml/windowitem/apps/test.windowitem.multiwin/main.qml2
-rw-r--r--tests/qml/windowitem/tst_windowitem.qml2
-rw-r--r--tests/qml/windowitem/windowitem.pro1
-rw-r--r--tests/qml/windowitem2/am-config.yaml10
-rw-r--r--tests/qml/windowitem2/apps/test.windowitem2.app/main.qml2
-rw-r--r--tests/qml/windowitem2/tst_windowitem2.qml2
-rw-r--r--tests/qml/windowitem2/windowitem2.pro1
-rw-r--r--tests/qml/windowmanager/IviApplicationExtension.qml2
-rw-r--r--tests/qml/windowmanager/am-config.yaml14
-rw-r--r--tests/qml/windowmanager/tst_windowmanager.qml2
-rw-r--r--tests/qml/windowmanager/windowmanager.pro3
-rw-r--r--tests/qml/windowmapping/am-config.yaml10
-rw-r--r--tests/qml/windowmapping/apps/test.winmap.amwin/amwin.qml2
-rw-r--r--tests/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml2
-rw-r--r--tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml2
-rw-r--r--tests/qml/windowmapping/apps/test.winmap.loader/loader.qml2
-rw-r--r--tests/qml/windowmapping/apps/test.winmap.ping/ping.qml2
-rw-r--r--tests/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml2
-rw-r--r--tests/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml2
-rw-r--r--tests/qml/windowmapping/apps/test.winmap.window/window.qml2
-rw-r--r--tests/qml/windowmapping/tst_windowmapping.qml2
-rw-r--r--tests/qml/windowmapping/windowmapping.pro8
-rw-r--r--tests/runtime/tst_runtime.cpp16
-rwxr-xr-xtests/signature/create-test-data.sh2
-rw-r--r--tests/signature/signature.pro2
-rw-r--r--tests/signature/tst_signature.cpp2
-rw-r--r--tests/sudo/sudo.pro2
-rw-r--r--tests/sudo/tst_sudo.cpp2
-rw-r--r--tests/systemreader/tst_systemreader.cpp2
-rw-r--r--tests/tests.pro3
-rw-r--r--tests/utilities/tst_utilities.cpp2
-rw-r--r--tests/yaml/data/cache1.yaml13
-rw-r--r--tests/yaml/data/cache2.yaml14
-rw-r--r--tests/yaml/data/test.yaml45
-rw-r--r--tests/yaml/tst_yaml.cpp340
-rw-r--r--tests/yaml/yaml.pro12
-rw-r--r--util/bash/appman-prompt10
542 files changed, 12843 insertions, 7405 deletions
diff --git a/.gitignore b/.gitignore
index 9cbabf18..4def785b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,7 +9,7 @@ moc_*
qrc_*
*.moc
*.user*
-Makefile
+Makefile*
core
DEADJOE
*.gcda
@@ -24,6 +24,7 @@ branch-coverage
.qmake.*
*.pch
*.log
+*.rcc
config.tests/*/*
!config.tests/*/*[.]*
@@ -48,3 +49,5 @@ src/tools/appman/config.qrc
doc/codeattributions.qdoc
examples/applicationmanager/custom-appman/custom-appman
tests/qml/crash/apps/tld.test.crash/terminator2/Terminator/
+examples/applicationmanager/fancyapps/apps/crash/Terminator/
+examples/applicationmanager/fancyapps/apps/widgets/widgets
diff --git a/.qmake.conf b/.qmake.conf
index ce2794aa..4a22cc51 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,6 +1,6 @@
load(qt_build_config)
-MODULE_VERSION = 5.13.2
+MODULE_VERSION = 5.14.0
SOURCE_DIR=$$PWD
BUILD_DIR=$$shadowed($$PWD)
diff --git a/application-manager.pro b/application-manager.pro
index 62771a35..75bc665c 100644
--- a/application-manager.pro
+++ b/application-manager.pro
@@ -1,9 +1,9 @@
requires(linux|android|macos|ios|win32:!winrt)
-!versionAtLeast(QT_VERSION, 5.11.2) {
- log("$$escape_expand(\\n\\n) *** The QtApplicationManager module needs to be built against Qt 5.11.2+ ***$$escape_expand(\\n\\n)")
- CONFIG += Qt_version_needs_to_be_at_least_5_11_2
+!versionAtLeast(QT_VERSION, 5.12.0) {
+ log("$$escape_expand(\\n\\n) *** The QtApplicationManager module needs to be built against Qt 5.12.0+ ***$$escape_expand(\\n\\n)")
+ CONFIG += Qt_version_needs_to_be_at_least_5_12_0
}
-requires(!Qt_version_needs_to_be_at_least_5_11_2)
+requires(!Qt_version_needs_to_be_at_least_5_12_0)
!tools-only:!qtHaveModule(qml):error("The QtQml library is required for a non 'tools-only' build")
@@ -116,6 +116,7 @@ OTHER_FILES += \
LICENSE.*[^~] \
config.tests/libarchive/* \
config.tests/libyaml/* \
+ config.tests/touchemulation/* \
util/bash/appman-prompt \
util/bash/README \
diff --git a/benchmarks/appman-bench/am-config.yaml b/benchmarks/appman-bench/am-config.yaml
index 3dd88817..21d47daf 100644
--- a/benchmarks/appman-bench/am-config.yaml
+++ b/benchmarks/appman-bench/am-config.yaml
@@ -3,9 +3,6 @@ formatType: am-configuration
---
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/apps"
- installedAppsManifestDir: "${CONFIG_PWD}/manifests"
- appImageMountDir: "${CONFIG_PWD}/image-mounts"
- database: "${CONFIG_PWD}/apps.db"
runtimes:
qml:
diff --git a/benchmarks/appman-bench/run.sh b/benchmarks/appman-bench/run.sh
index eb5b894c..e79846bd 100755
--- a/benchmarks/appman-bench/run.sh
+++ b/benchmarks/appman-bench/run.sh
@@ -1,11 +1,12 @@
#!/bin/bash
#############################################################################
##
+## Copyright (C) 2019 The Qt Company Ltd.
## Copyright (C) 2019 Luxoft Sweden AB
## Copyright (C) 2018 Pelagicore AG
## Contact: https://www.qt.io/licensing/
##
-## This file is part of the Luxoft Application Manager.
+## This file is part of the Qt Application Manager.
##
## $QT_BEGIN_LICENSE:BSD-QTAS$
## Commercial License Usage
@@ -117,7 +118,7 @@ run_test()
echo "Running $test_qml in $temp_folder"
cp $test_qml $temp_folder/test.qml
- (cd $temp_folder && $APPMAN -c am-config.yaml -r --no-dlt-logging)
+ (cd $temp_folder && $APPMAN -c am-config.yaml --clear-cache --no-dlt-logging)
}
if [ -n "$TEST" ]
diff --git a/benchmarks/appman-bench/system-ui/main.qml b/benchmarks/appman-bench/system-ui/main.qml
index 762303ac..fa7de877 100644
--- a/benchmarks/appman-bench/system-ui/main.qml
+++ b/benchmarks/appman-bench/system-ui/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/benchmarks/appman-bench/templates/appman-qml/main.qml b/benchmarks/appman-bench/templates/appman-qml/main.qml
index b15ea8aa..87b4597c 100644
--- a/benchmarks/appman-bench/templates/appman-qml/main.qml
+++ b/benchmarks/appman-bench/templates/appman-qml/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/benchmarks/appman-bench/templates/qmlscene/main.qml b/benchmarks/appman-bench/templates/qmlscene/main.qml
index f31cc6a2..2d1dcf6e 100644
--- a/benchmarks/appman-bench/templates/qmlscene/main.qml
+++ b/benchmarks/appman-bench/templates/qmlscene/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/benchmarks/appman-bench/tests/controls2.qml b/benchmarks/appman-bench/tests/controls2.qml
index 169d6163..f34db8a2 100644
--- a/benchmarks/appman-bench/tests/controls2.qml
+++ b/benchmarks/appman-bench/tests/controls2.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/benchmarks/appman-bench/tests/rect.qml b/benchmarks/appman-bench/tests/rect.qml
index c033e910..f5fbec06 100644
--- a/benchmarks/appman-bench/tests/rect.qml
+++ b/benchmarks/appman-bench/tests/rect.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/benchmarks/appman-bench/tests/repeater.qml b/benchmarks/appman-bench/tests/repeater.qml
index 2866e50d..fb759ceb 100644
--- a/benchmarks/appman-bench/tests/repeater.qml
+++ b/benchmarks/appman-bench/tests/repeater.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/benchmarks/appman-bench/tests/shader.qml b/benchmarks/appman-bench/tests/shader.qml
index e69d0a55..3aad12a1 100644
--- a/benchmarks/appman-bench/tests/shader.qml
+++ b/benchmarks/appman-bench/tests/shader.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/config.tests/libarchive/main.cpp b/config.tests/libarchive/main.cpp
index 53515610..58b21a4d 100644
--- a/config.tests/libarchive/main.cpp
+++ b/config.tests/libarchive/main.cpp
@@ -5,7 +5,7 @@
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/config.tests/libyaml/main.cpp b/config.tests/libyaml/main.cpp
index 546b2634..f6c5442c 100644
--- a/config.tests/libyaml/main.cpp
+++ b/config.tests/libyaml/main.cpp
@@ -5,7 +5,7 @@
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/config.tests/touchemulation/main.cpp b/config.tests/touchemulation/main.cpp
index 1b012d8f..92ed9484 100644
--- a/config.tests/touchemulation/main.cpp
+++ b/config.tests/touchemulation/main.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/doc/QtApplicationManagerDoc b/doc/QtApplicationManagerDoc
index 333bf5a6..ccd77195 100644
--- a/doc/QtApplicationManagerDoc
+++ b/doc/QtApplicationManagerDoc
@@ -4,7 +4,6 @@
#include <QtAppManCommon/QtAppManCommon>
#include <QtAppManCrypto/QtAppManCrypto>
#include <QtAppManDBus/QtAppManDBus>
-#include <QtAppManInstaller/QtAppManInstaller>
#include <QtAppManIntentClient/QtAppManIntentClient>
#include <QtAppManIntentServer/QtAppManIntentServer>
#include <QtAppManLauncher/QtAppManLauncher>
diff --git a/doc/applicationmanager-project.qdocconf b/doc/applicationmanager-project.qdocconf
index d4446bd4..0e70d0d8 100644
--- a/doc/applicationmanager-project.qdocconf
+++ b/doc/applicationmanager-project.qdocconf
@@ -12,6 +12,8 @@ headers.fileextensions = "*.h *.ch *.h++ *.hh *.hpp *.hxx"
examples.fileextensions = "*.cpp *.h *.qml *.yaml"
examples.imageextensions = "*.png *.jpg *.gif"
+include(config/exampleurl-qtapplicationmanager.qdocconf)
+
headerdirs += \
../src/common-lib \
../src/shared-main-lib \
@@ -19,7 +21,6 @@ headerdirs += \
../src/manager-lib \
../src/application-lib \
../src/package-lib \
- ../src/installer-lib \
../src/intent-client-lib \
../src/intent-server-lib \
../src/notification-lib \
@@ -37,7 +38,6 @@ sourcedirs += \
../src/manager-lib \
../src/application-lib \
../src/package-lib \
- ../src/installer-lib \
../src/intent-client-lib \
../src/intent-server-lib \
../src/notification-lib \
diff --git a/doc/config/exampleurl-qtapplicationmanager.qdocconf b/doc/config/exampleurl-qtapplicationmanager.qdocconf
new file mode 100644
index 00000000..a0e5f4c3
--- /dev/null
+++ b/doc/config/exampleurl-qtapplicationmanager.qdocconf
@@ -0,0 +1 @@
+url.examples = "https://code.qt.io/cgit/qt/qtapplicationmanager.git/tree/examples/\1?h=$QT_VER"
diff --git a/doc/configuration.qdoc b/doc/configuration.qdoc
index 4b7d646f..15ea0acc 100644
--- a/doc/configuration.qdoc
+++ b/doc/configuration.qdoc
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
@@ -102,7 +103,7 @@ or across multiple config files, the final value is resolved based on these rule
\li bool
\li Prints the build configuration of the application manager in YAML format and exits.
\row
- \li \b --config-file or \b{\c -c}
+ \li \b --config-file or \b -c
\li array<string>
\li Loads configuration settings from a set of files. You can use more than one config
file, for example, to split the configuration cleanly, into a device specific and a
@@ -122,17 +123,24 @@ or across multiple config files, the final value is resolved based on these rule
(default: \c /opt/am/config.yaml)
\row
- \li \b --no-config-cache
+ \li \b --no-cache
\li bool
- \li Disables the caching functionality for the configuration files: the cache is neither
- read from or written to.
+ \li Disables the caching functionality for the configuration files and the application
+ database : the caches are neither read from or written to.
+ (default: false)
\row
- \li \b --clear-config-cache
+ \li \b --clear-cache
\li bool
- \li Although the application manager should detect if the configuration file cache is out
- of sync, you can force-clear the cache on startup with this option.
+ \li Although the application manager should detect if the configuration file and application
+ database caches are out of sync, you can force-clear the caches on startup with this
+ option.
+
+ The old options \c --clear-config-cache, \c -r, and \c --recreate-database are also still
+ supported and do also - despite their names - clear both caches.
+
+ (default: false)
\row
- \li \b --option or \b{\c -o}
+ \li \b --option or \b -o
\li YAML
\li Use this option to set or overwrite parts of your config files from the command line.
This option can be specified multiple times and its values are evaluated the same way
@@ -143,15 +151,15 @@ or across multiple config files, the final value is resolved based on these rule
\li \b --database
\br [\c applications/database]
\li string
- \li To decrease the startup time of the System UI, its application database can be cached
- in a file. This way, in subsequent startups, the System UI doesn't have to scan and
- parse the \c info.yaml files for the applications installed, all over again. This
- option specifies the path for this cache file. (default: empty/disabled)
+ \li Deprecated and ignored. The application database will transparently be cached - see also
+ the \c --clear-cache and \c --no-cache options.
\row
- \li \b --recreate-database or \b{\c -r}
+ \li \b --recreate-database or \b -r
\li bool
- \li Ignores any pre-existing database cache and creates a new one by (re)scanning all
- \c info.yaml files in \c builtin-apps-manifest-dir and \c installed-apps-manifest-dir.
+ \li Deprecated. These options were necessary for the application-manager to react on changes
+ to the application manifest files, but this is not needed anymore. For backward
+ compatibility these options do map to the \c --clear-cache option, which will clear both
+ the configuration and application database cache.
(default: false)
\row
\li \b --builtin-apps-manifest-dir
@@ -160,18 +168,18 @@ or across multiple config files, the final value is resolved based on these rule
\li The base directory for built-in application manifests; you can also specify multiple
directories as a list.
\row
- \li \b --installed-apps-manifest-dir
- \br [\c applications/installedAppsManifestDir]
+ \li \b --installation-dir
+ \br [\c applications/installationDir]
\li string
- \li The base directory for installed application manifests. This option must be specified
- if you want to install new applications; otherwise only the built-in ones are
+ \li The base directory for package installations. This option must be specified
+ if you want to install new package; otherwise only the built-in ones are
available. (default: empty/disabled)
\row
- \li \b --app-image-mount-dir
- \br [\c applications/appImageMountDir]
+ \li \b --document-dir
+ \br [\c applications/documentDir]
\li string
- \li The base directory where application images are mounted to.
- (defaults: \c /opt/am/image-mounts)
+ \li The base directory for per-package document storage directories.
+ (default: empty/disabled)
\row
\li \b --dbus
\li string
@@ -230,6 +238,12 @@ or across multiple config files, the final value is resolved based on these rule
\li string
\li If set, the given style is used by QtQuickControls 2.
\row
+ \li [\c ui/resources]
+ \li array<string>
+ \li Takes a list of \l{The Qt Resource System}{Qt resource} files (.rcc) or libraries that
+ have resources \l{Compiled-In Resources}{compiled-in} and registers them within the
+ System UI process. Resources can be accessed with the ":" or "qrc://" file path prefix.
+ \row
\li [\c plugins]
\li map<array<string>>
\li A string-to-string-list map that defines plugins that the application manager should
@@ -357,8 +371,9 @@ or across multiple config files, the final value is resolved based on these rule
\row
\li [\c installationLocations]
\li array<object>
- \li The definition of installation locations available on the system; an array of
- \l {Installation Locations} objects.
+ \li The definition of installation locations available on the system. This is deprecated,
+ since only a single installation location is supported now, defined by \c
+ --installationDir or \c{applications/installationDir}.
\row
\li [\c runtimes]
\li map<object>
@@ -499,52 +514,6 @@ of these available interfaces are as follows:
\l {freedesktop.org specification}
\endtable
-\section1 Installation Locations
-
-The \c installationLocations YAML field is a list of YAML objects, very similar to
-ApplicationInstaller::getInstallationLocation.
-
-\table
- \header
- \li Config Key
- \li Type
- \li Description
- \row
- \li \c id
- \li string
- \li The installation location ID that is used as the handle for all other
- ApplicationInstaller function calls. The \c id consists of a \c type and \c index
- field, concatenated with a single dash. For example, \c removable-0.
-
- Valid values for \c type are \c internal and \c removable.
-
- In case there is more than one installation location for the same type of device, this
- zero-based index is used for disambiguation. For example, two SD card slots will result
- in the IDs \c removable-0 and \c removable-1. Otherwise, the index is always \c 0.
- \row
- \li \c isDefault
- \li bool
- \li Only one installation location can be the default location, which must be mounted and
- accessible at all times. This location can be used by a UI application to get a
- sensible default for the installation location that it needs to pass to
- \l{ApplicationInstaller::startPackageInstallation()}{startPackageInstallation()}.
- \row
- \li \c installationPath
- \li string
- \li The absolute file system path to the base directory where applications are installed.
- \row
- \li \c documentPath
- \li string
- \li The absolute file system path to the base directory where per-user document directories
- are created. This entry can either be located on this device, or it can be the same as
- the \c documentPath of the master installation location.
- \row
- \li \c mountPoint
- \li string
- \li Only required for \c removable installation location: The absolute file system path to
- the mount-point of the device, where \c installationPath is located.
-\endtable
-
\section1 Runtime Configuration
The runtime configuration sub-objects are specific to the actual runtimes, so the table below has
@@ -585,6 +554,14 @@ an additional column specifying which runtime a configuration option applies to:
calls the function hooks on application startup.
\endlist
\row
+ \li [\c resources]
+ \li qml
+ \li array<string>
+ \li Takes a list of \l{The Qt Resource System}{Qt resource} files (.rcc) or libraries that
+ have resources \l{Compiled-In Resources}{compiled-in} and registers them within each
+ QML runtime. Consequently, all running QML applications will include these resources.
+ The resources can be accessed with the ":" or "qrc://" file path prefix.
+ \row
\li \c quicklaunchQml
\li qml
\li string
diff --git a/doc/container.qdoc b/doc/container.qdoc
index dd6322b7..cbb8d182 100644
--- a/doc/container.qdoc
+++ b/doc/container.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/doc/controller.qdoc b/doc/controller.qdoc
index 6b6511c9..42af67c9 100644
--- a/doc/controller.qdoc
+++ b/doc/controller.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
@@ -85,9 +85,6 @@ The following commands are available:
\li Installs the package given on the command-line. If the package file is specified as \c{-},
the tool tries to read the package from \c stdin. The following options are supported:
- \c{-l, --location}: Install to a specific installation location
- (see \c show-installation-location).
-
\c{-a, --acknowledge}: Automatically acknowledge the installation, instead of relying on
the System UI's logic.
\row
diff --git a/doc/debugging.qdoc b/doc/debugging.qdoc
index c1ecfe05..687e1fa7 100644
--- a/doc/debugging.qdoc
+++ b/doc/debugging.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/doc/elements-apps.qdoc b/doc/elements-apps.qdoc
index fc62c2d3..7bbbe9c1 100644
--- a/doc/elements-apps.qdoc
+++ b/doc/elements-apps.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
@@ -37,7 +37,7 @@ application.
Singleton QML types need not be declared, they are referenced by their type name.
-Instantiable QML types are declared with the their name followed by curly braces. These
+Instantiable QML types are declared with their name followed by curly braces. These
declarations may be nested, creating parent-child relationships between the items.
\section1 QML Singletons
diff --git a/doc/elements-common.qdoc b/doc/elements-common.qdoc
index bcd505c4..5853c46d 100644
--- a/doc/elements-common.qdoc
+++ b/doc/elements-common.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
@@ -37,7 +37,7 @@ and applications.
Singleton QML types need not be declared, they are referenced by their type name.
-Instantiable QML types are declared with the their name followed by curly braces. These
+Instantiable QML types are declared with their name followed by curly braces. These
declarations may be nested, creating parent-child relationships between the items.
\section1 QML Singletons
diff --git a/doc/elements-systemui.qdoc b/doc/elements-systemui.qdoc
index df5df122..c82eba0f 100644
--- a/doc/elements-systemui.qdoc
+++ b/doc/elements-systemui.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
@@ -37,7 +37,7 @@ System UI.
Singleton QML types need not be declared, they are referenced by their type name.
-Instantiable QML types are declared with the their name followed by curly braces. These
+Instantiable QML types are declared with their name followed by curly braces. These
declarations may be nested, creating parent-child relationships between the items.
Non-Instantiable QML types are return values provided to the System UI code, that allow the user
diff --git a/doc/index.qdoc b/doc/index.qdoc
index 24dc9057..eea6a238 100644
--- a/doc/index.qdoc
+++ b/doc/index.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
@@ -50,6 +50,7 @@ For a high-level overview, see \l{The Qt Application Manager}{Introduction to th
\li \l{Application Installer}
\li \l{Logging and Debugging}
\li \l{Containers}
+ \li \l{Use Qt Resources}
\li \l{Single-Process vs. Multi-Process Mode}
\li \l{Migrating code from 5.11 to 5.12}
\endlist
diff --git a/doc/installation.qdoc b/doc/installation.qdoc
index c7b59c14..d6ba3be2 100644
--- a/doc/installation.qdoc
+++ b/doc/installation.qdoc
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
@@ -81,7 +82,7 @@ to single-process mode, if certain dependencies are not available, such as:
You can force the build mode via the respective \c -config options \c force-multi-process and
\c force-single-process, as described below.
-
+\target build
\section1 Build
The application manager uses \c qmake for its build system. The basic installation steps are:
@@ -264,10 +265,10 @@ With everything in place, you can start the application manager:
\badcode
cd /path/to/system-ui
-appman -c /opt/am/config.yaml -c am-config.yaml -r --verbose main.qml
+appman -c /opt/am/config.yaml -c am-config.yaml --verbose main.qml
\endcode
-\c{-r} makes sure to recreate the apps database and \c{--verbose} gives you verbose output,
-which is quite helpful when first setting up the environment.
+\c{--verbose} gives you verbose output, which is quite helpful when first setting up the environment
+and also for debugging purposes.
*/
diff --git a/doc/installer.qdoc b/doc/installer.qdoc
index 74016e6a..54989990 100644
--- a/doc/installer.qdoc
+++ b/doc/installer.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/doc/introduction.qdoc b/doc/introduction.qdoc
index abf4610e..53eefb33 100644
--- a/doc/introduction.qdoc
+++ b/doc/introduction.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/doc/manifest.qdoc b/doc/manifest.qdoc
index 14d68969..b73310fa 100644
--- a/doc/manifest.qdoc
+++ b/doc/manifest.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
@@ -271,6 +271,13 @@ that specifies which runtime a configuration option applies to:
\li A list of paths to add to the QML-engine's import paths. Use of this parameter is
equivalent to setting \c QML2_IMPORT_PATH for a program started from the command line.
\row
+ \li \c resources
+ \li qml, qml-in-process
+ \li array<string>
+ \li Takes a list of \l{The Qt Resource System}{Qt resource} files (.rcc) or libraries that have
+ resources \l{Compiled-In Resources}{compiled-in} and registers them within the application
+ process. Resources can be accessed with the ":" or "qrc://" file path prefix.
+\row
\li \c pluginPaths
\li qml, qml-in-process
\li array<string>
diff --git a/doc/migration-guide-5.12.qdoc b/doc/migration-guide-5.12.qdoc
index 52ab19ff..f25b4f03 100644
--- a/doc/migration-guide-5.12.qdoc
+++ b/doc/migration-guide-5.12.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/doc/package-format.qdoc b/doc/package-format.qdoc
index 68d47ccc..8e49492d 100644
--- a/doc/package-format.qdoc
+++ b/doc/package-format.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/doc/packager.qdoc b/doc/packager.qdoc
index aba3fdd9..87bef980 100644
--- a/doc/packager.qdoc
+++ b/doc/packager.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/doc/qmlmodule.qdoc b/doc/qmlmodule.qdoc
index a297eb65..16181370 100644
--- a/doc/qmlmodule.qdoc
+++ b/doc/qmlmodule.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/doc/resources.qdoc b/doc/resources.qdoc
new file mode 100644
index 00000000..7735914d
--- /dev/null
+++ b/doc/resources.qdoc
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:FDL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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$
+**
+****************************************************************************/
+
+/*!
+
+\page use-qt-resources.html
+\title Use Qt Resources
+
+\l{The Qt Resource System} lets you store files in your program's executable. In some ways,
+this feature resembles a dedicated file system, which we call \e{resource file system}. Usually,
+this file system contains QML code and other assets like images. If you use the QML compiler, the
+compiled code is always placed in the resource file system. There are a few application manager
+specific considerations, especially when your application needs to support both single-process and
+multi-process modes.
+
+\section1 Compile Resources
+
+You can add resources as \l{External Binary Resources}{external binary resources} or as
+\l{Compiled-In Resources}{compiled-in resources}; both are generated from a \c .qrc file.
+Typically, external binary resources are stored in a file with the \c .rcc extension, whereas
+compiled-in resources are stored in libraries in the Application Manager context.
+
+It's important to understand that each process has its own resource file system. Consequently, to
+support multi-process mode, resources must be generated separately for the System UI and for each
+application. Conversely, in single-process mode there is only one resource file system and you must
+ensure that file paths don't clash. To prevent clashes, we recommend to prefix each application
+file path with the unique application ID.
+
+Consider the following application file structure:
+
+\badcode
+apps
+|---- app1
+| |---- main.qml
+| |---- app1.qrc
+| ...
+|---- app2
+| |---- main.qml
+| |---- app2.qrc
+| ...
+\endcode
+
+Without a prefix, in single-process mode, the \c main.qml files would clash. To avoid this, the
+\c .qrc file for app1 should read like this:
+
+\badcode
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="app1">
+ <file>main.qml</file>
+</qresource>
+</RCC>
+\endcode
+
+For \c app2 the prefix should be "app2", respectively. Generally, all files contained in any
+\c .qrc file should be unique; this also includes files that the System UI uses.
+
+
+\section1 Load Resources
+
+In addition to the approaches described in \l{The Qt Resource System}, the Application Manager
+provides configuration options to load resources, both -- external binary resources and
+compiled-in resources in the form of a library.
+
+Suppose you have a \c my.rcc binary file and a \c myplugin.so library file. These can be loaded
+into the System UI by adding the following lines to the \c am-config.yaml file:
+
+\badcode
+ui:
+ resources: [ "${CONFIG_PWD}/my.rcc",
+ "${CONFIG_PWD}/myplugin.so" ]
+\endcode
+
+You can also load these two files into an application by adding the following snippet to the
+\c info.yaml file:
+
+\badcode
+runtimeParameters:
+ resources: [ "my.rcc",
+ "myplugin.so" ]
+\endcode
+
+The resources are loaded when the System UI starts, before the QML engine is instantiated. In
+multi-process mode the application resources are also loaded into the application process at
+startup. In single-process mode, resources are loaded when the application first starts and then
+reused on subsequent invocations; they are never unloaded.
+
+\section1 Access Resources
+
+The application manager allows for file access in the resource file system, either with the URL
+scheme (\c{qrc}) or the file name prefix (\c{:}). Both these options require an absolute file path
+in the resource file system, such as:
+
+\list
+ \li \c{qrc:/app1/main.qml} or \c{qrc:///app1/main.qml}
+ \li \c{:/app1/main.qml}
+\endlist
+
+While the Qt Application Manager accepts this relaxed naming structure, the QML engine
+distinguishes between URLs and file names. For instance, an \l{Image::source}
+{Image source} property only accepts the \c{qrc} scheme.
+
+If you want to specify a relative path, don't use the scheme or file path prefix.
+
+If your files aren't found in the resource file system, you can list the contents of the entire
+resource file system with the following code snippet:
+
+\code
+QDirIterator it(qSL(":"), QDirIterator::Subdirectories);
+while (it.hasNext()) {
+ const QString fn = it.next();
+ if (!fn.startsWith(qSL(":/qt-project.org"))) // exclude Qt internal files
+ qDebug() << fn;
+}
+\endcode
+
+*/
diff --git a/doc/singlevsmultiprocess.qdoc b/doc/singlevsmultiprocess.qdoc
index 0fffe168..767aa099 100644
--- a/doc/singlevsmultiprocess.qdoc
+++ b/doc/singlevsmultiprocess.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/doc/systemui.qdoc b/doc/systemui.qdoc
index ff800067..44a2a3a6 100644
--- a/doc/systemui.qdoc
+++ b/doc/systemui.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
@@ -104,7 +104,7 @@ One example of a simple System UI is the one written for the "Hello World!" Syst
\quotefromfile ../examples/applicationmanager/hello-world/system-ui.qml
\skipto Item {
-\printuntil
+\printuntil /^\}/
\section2 Notifications
diff --git a/doc/troubleshooting.qdoc b/doc/troubleshooting.qdoc
index 48610b96..fd05bfc0 100644
--- a/doc/troubleshooting.qdoc
+++ b/doc/troubleshooting.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/doc/write-applications.qdoc b/doc/write-applications.qdoc
index 7c13c151..e492c4c4 100644
--- a/doc/write-applications.qdoc
+++ b/doc/write-applications.qdoc
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
@@ -38,8 +39,7 @@ stand-alone QML application, except for these three additional tasks:
\li If you write a QML application, make your QML scene's root element an
ApplicationManagerWindow; or derive your own custom root item from it.
\li Provide a valid \l{Manifest definition}{info.yaml} file.
- \li Make the application manager aware of your application by running
- \c{appman --recreate-database}.
+ \li Restart the application manager to make it aware of your application.
\endlist
\section2 The Root Element
diff --git a/doc/yaml.qdoc b/doc/yaml.qdoc
index b87c5eaf..8ee10d4b 100644
--- a/doc/yaml.qdoc
+++ b/doc/yaml.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/animated-windows/animated-windows.pro b/examples/applicationmanager/animated-windows/animated-windows.pro
index 539906b7..0e929759 100644
--- a/examples/applicationmanager/animated-windows/animated-windows.pro
+++ b/examples/applicationmanager/animated-windows/animated-windows.pro
@@ -22,7 +22,7 @@ AM_COPY_FILES += am-config.yaml
prefix_build:tpath = $$target.path
else:tpath = $$_PRO_FILE_PWD_
-AM_DEFAULT_ARGS = -c $$tpath/am-config.yaml --verbose -r
+AM_DEFAULT_ARGS = -c $$tpath/am-config.yaml --verbose
example_sources.path = $$target.path
example_sources.files = $$AM_COPY_FILES $$AM_COPY_DIRECTORIES
diff --git a/examples/applicationmanager/animated-windows/apps/animated-windows.fish/fish.qml b/examples/applicationmanager/animated-windows/apps/animated-windows.fish/fish.qml
index 1c6a56e5..60e64926 100644
--- a/examples/applicationmanager/animated-windows/apps/animated-windows.fish/fish.qml
+++ b/examples/applicationmanager/animated-windows/apps/animated-windows.fish/fish.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/animated-windows/apps/animated-windows.rabbit/rabbit.qml b/examples/applicationmanager/animated-windows/apps/animated-windows.rabbit/rabbit.qml
index 4b5892b0..42a2cfab 100644
--- a/examples/applicationmanager/animated-windows/apps/animated-windows.rabbit/rabbit.qml
+++ b/examples/applicationmanager/animated-windows/apps/animated-windows.rabbit/rabbit.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/animated-windows/doc/src/animated-windows.qdoc b/examples/applicationmanager/animated-windows/doc/src/animated-windows.qdoc
index d412054c..efdb3157 100644
--- a/examples/applicationmanager/animated-windows/doc/src/animated-windows.qdoc
+++ b/examples/applicationmanager/animated-windows/doc/src/animated-windows.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/animated-windows/system-ui/main.qml b/examples/applicationmanager/animated-windows/system-ui/main.qml
index cab98951..fd64b494 100644
--- a/examples/applicationmanager/animated-windows/system-ui/main.qml
+++ b/examples/applicationmanager/animated-windows/system-ui/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/application-features/am-config.yaml b/examples/applicationmanager/application-features/am-config.yaml
new file mode 100644
index 00000000..76dc4e7d
--- /dev/null
+++ b/examples/applicationmanager/application-features/am-config.yaml
@@ -0,0 +1,24 @@
+formatVersion: 1
+formatType: am-configuration
+---
+applications:
+ builtinAppsManifestDir: "${CONFIG_PWD}/apps"
+ installationDir: "/tmp/application-features/apps"
+
+logging:
+ rules:
+ - "*=false"
+ - "qt.*=false"
+ - "am.*=false"
+ - "qml*=true"
+ - "*.warning=true"
+ - "*.critical=true"
+
+ui:
+ fullscreen: no
+ mainQml: "${CONFIG_PWD}/system-ui/main.qml"
+
+# development setup:
+flags:
+ noSecurity: yes
+ noUiWatchdog: yes
diff --git a/examples/applicationmanager/application-features/application-features.pro b/examples/applicationmanager/application-features/application-features.pro
new file mode 100644
index 00000000..f986222b
--- /dev/null
+++ b/examples/applicationmanager/application-features/application-features.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+SUBDIRS = ui.pro \
+ imports \
+ native
diff --git a/examples/applicationmanager/application-features/application-features.qmlproject b/examples/applicationmanager/application-features/application-features.qmlproject
new file mode 100644
index 00000000..33df4360
--- /dev/null
+++ b/examples/applicationmanager/application-features/application-features.qmlproject
@@ -0,0 +1,17 @@
+import QmlProject 1.1
+
+Project {
+ mainFile: "system-ui/main.qml"
+
+ QmlFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+ Files {
+ directory: "."
+ filter: "*.yaml"
+ }
+}
+
diff --git a/examples/applicationmanager/application-features/apps/compositor/compositor.qml b/examples/applicationmanager/application-features/apps/compositor/compositor.qml
new file mode 100644
index 00000000..c6979158
--- /dev/null
+++ b/examples/applicationmanager/application-features/apps/compositor/compositor.qml
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+
+import QtQuick 2.11
+import QtApplicationManager.Application 2.0
+import QtWayland.Compositor 1.3
+
+ApplicationManagerWindow {
+ id: root
+ color: "lightgrey"
+
+ property ListModel shellSurfaces: ListModel {}
+
+ Text {
+ anchors.fill: parent
+ anchors.margins: 8
+ font.pointSize: 14
+ wrapMode: Text.Wrap
+ textFormat: Text.RichText
+ text: "This Wayland<sup>*</sup> client window implements a Wayland compositor (nested compositor). " +
+ "To display Wayland clients here, set:<br><br><b>WAYLAND_DISPLAY=qtam-wayland-nested</b>" +
+ "<br><br>For instance:<br>WAYLAND_DISPLAY=qtam-wayland-nested qmlscene client.qml -platform wayland" +
+ "<br><br><small>* in multi-process mode</small>"
+ }
+
+ WaylandCompositor {
+ socketName: "qtam-wayland-nested"
+
+ WaylandOutput {
+ window: root
+ sizeFollowsWindow: true
+ }
+
+ WlShell {
+ onWlShellSurfaceCreated: shellSurfaces.append({shellSurface: shellSurface});
+ }
+
+ XdgShellV6 {
+ onToplevelCreated: shellSurfaces.append({shellSurface: xdgSurface});
+ }
+
+ XdgShell {
+ onToplevelCreated: shellSurfaces.append({shellSurface: xdgSurface});
+ }
+ }
+
+ Repeater {
+ model: shellSurfaces
+ ShellSurfaceItem {
+ shellSurface: modelData
+ onSurfaceDestroyed: shellSurfaces.remove(index)
+ }
+ }
+
+ Component.onCompleted: console.info("Start a client application in the nested compositor for instance with:\n " +
+ "WAYLAND_DISPLAY=qtam-wayland-nested QT_WAYLAND_DISABLE_WINDOWDECORATION=1 " +
+ "QT_WAYLAND_SHELL_INTEGRATION=xdg-shell qmlscene client.qml -platform wayland");
+}
diff --git a/examples/applicationmanager/application-features/apps/compositor/icon.png b/examples/applicationmanager/application-features/apps/compositor/icon.png
new file mode 100644
index 00000000..7648da9b
--- /dev/null
+++ b/examples/applicationmanager/application-features/apps/compositor/icon.png
Binary files differ
diff --git a/examples/applicationmanager/application-features/apps/compositor/info.yaml b/examples/applicationmanager/application-features/apps/compositor/info.yaml
new file mode 100644
index 00000000..c122f66b
--- /dev/null
+++ b/examples/applicationmanager/application-features/apps/compositor/info.yaml
@@ -0,0 +1,9 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'compositor'
+icon: 'icon.png'
+code: 'compositor.qml'
+runtime: 'qml'
+name:
+ en: 'Nested Compositor'
diff --git a/examples/applicationmanager/application-features/apps/crash/crashapp.qml b/examples/applicationmanager/application-features/apps/crash/crashapp.qml
new file mode 100644
index 00000000..4db96568
--- /dev/null
+++ b/examples/applicationmanager/application-features/apps/crash/crashapp.qml
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.11
+import QtApplicationManager.Application 2.0
+import Terminator 2.0
+
+ApplicationManagerWindow {
+ id: root
+
+ property var methods: ({ illegalMemory: "Illegal memory access",
+ illegalMemoryInThread: "Illegal memory access in a thread",
+ stackOverflow: "Force stack overflow",
+ divideByZero: "Divide by zero",
+ unhandledException: "Throw unhandled exception",
+ abort: "Call abort",
+ raise: "Raise signal 7",
+ gracefully: "Exit gracefully" })
+
+
+ function accessIllegalMemory()
+ {
+ Terminator.accessIllegalMemory();
+ }
+
+ Grid {
+ columns: 2
+ Repeater {
+ model: Object.keys(methods)
+ Rectangle {
+ width: root.width / 2
+ height: root.height / 4
+ border.width: 1
+ color: "lightgrey"
+
+ Text {
+ anchors.fill: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ wrapMode: Text.Wrap
+ font.pointSize: 14
+ text: methods[modelData]
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ switch (modelData) {
+ case "illegalMemory": accessIllegalMemory(); break;
+ case "illegalMemoryInThread": Terminator.accessIllegalMemoryInThread(); break;
+ case "stackOverflow": Terminator.forceStackOverflow(); break;
+ case "divideByZero": Terminator.divideByZero(); break;
+ case "unhandledException": Terminator.throwUnhandledException(); break;
+ case "abort": Terminator.abort(); break;
+ case "raise": Terminator.raise(7); break;
+ case "gracefully": Terminator.exitGracefully(); break;
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/examples/applicationmanager/application-features/apps/crash/icon.png b/examples/applicationmanager/application-features/apps/crash/icon.png
new file mode 100644
index 00000000..c3e6f8d4
--- /dev/null
+++ b/examples/applicationmanager/application-features/apps/crash/icon.png
Binary files differ
diff --git a/examples/applicationmanager/application-features/apps/crash/info.yaml b/examples/applicationmanager/application-features/apps/crash/info.yaml
new file mode 100644
index 00000000..50bafe2a
--- /dev/null
+++ b/examples/applicationmanager/application-features/apps/crash/info.yaml
@@ -0,0 +1,11 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'crash'
+icon: 'icon.png'
+code: 'crashapp.qml'
+runtime: 'qml'
+name:
+ en: 'Crash Simulation'
+runtimeParameters:
+ importPaths: [ "." ]
diff --git a/examples/applicationmanager/application-features/apps/twins/icon.png b/examples/applicationmanager/application-features/apps/twins/icon.png
new file mode 100644
index 00000000..3a3cb0bb
--- /dev/null
+++ b/examples/applicationmanager/application-features/apps/twins/icon.png
Binary files differ
diff --git a/examples/applicationmanager/application-features/apps/twins/info.yaml b/examples/applicationmanager/application-features/apps/twins/info.yaml
new file mode 100644
index 00000000..580445bf
--- /dev/null
+++ b/examples/applicationmanager/application-features/apps/twins/info.yaml
@@ -0,0 +1,9 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'twins'
+icon: 'icon.png'
+code: 'twins.qml'
+runtime: 'qml'
+name:
+ en: 'Two Top-Level Windows'
diff --git a/examples/applicationmanager/application-features/apps/twins/twins.qml b/examples/applicationmanager/application-features/apps/twins/twins.qml
new file mode 100644
index 00000000..09134efc
--- /dev/null
+++ b/examples/applicationmanager/application-features/apps/twins/twins.qml
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+
+import QtQuick 2.11
+import QtApplicationManager.Application 2.0
+
+QtObject {
+ property var win1: ApplicationManagerWindow {
+ color: "lightsteelblue"
+
+ Rectangle {
+ width: 80; height: 80; radius: 40
+ color: "orange"
+
+ MouseArea {
+ anchors.fill: parent
+ drag.target: parent
+ }
+ }
+ }
+
+ property var win2: ApplicationManagerWindow {
+ color: "transparent"
+
+ Rectangle {
+ id: rect
+ anchors.fill: parent
+ color: "orange"
+ opacity: 0.4
+ }
+
+ ApplicationManagerWindow {
+ id: popup
+ width: 300; height: 100
+
+ Rectangle {
+ anchors.fill: parent
+ border.width: 1
+ color: "orangered"
+ }
+
+ Text {
+ anchors.centerIn: parent
+ text: "Click to hide!"
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: popup.visible = false;
+ }
+
+ Component.onCompleted: setWindowProperty("type", "pop-up");
+ }
+ }
+}
diff --git a/examples/applicationmanager/application-features/apps/widgets/icon.png b/examples/applicationmanager/application-features/apps/widgets/icon.png
new file mode 100644
index 00000000..cfcd8fcb
--- /dev/null
+++ b/examples/applicationmanager/application-features/apps/widgets/icon.png
Binary files differ
diff --git a/examples/applicationmanager/application-features/apps/widgets/info.yaml b/examples/applicationmanager/application-features/apps/widgets/info.yaml
new file mode 100644
index 00000000..7e90e2ab
--- /dev/null
+++ b/examples/applicationmanager/application-features/apps/widgets/info.yaml
@@ -0,0 +1,13 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'widgets'
+name:
+ en: 'Native Widgets'
+icon: 'icon.png'
+code: 'widgets'
+runtime: 'native'
+runtimeParameters:
+ environmentVariables:
+ QT_WAYLAND_DISABLE_WINDOWDECORATION: "1"
+supportsApplicationInterface: yes
diff --git a/examples/applicationmanager/application-features/client.qml b/examples/applicationmanager/application-features/client.qml
new file mode 100644
index 00000000..b761a656
--- /dev/null
+++ b/examples/applicationmanager/application-features/client.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+
+import QtQuick 2.11
+
+Rectangle {
+ id: root
+
+ width: 320
+ height: 240
+ color: "lightsteelblue"
+
+ Rectangle {
+ anchors.centerIn: parent
+ width: 180; height: 180; radius: width/4
+ color: "orange"
+
+ RotationAnimation on rotation {
+ id: rotation
+ from: 0; to: 360; loops: Animation.Infinite; duration: 2000
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: rotation.paused = !rotation.paused
+ }
+ }
+}
diff --git a/examples/applicationmanager/application-features/doc/images/application-features.png b/examples/applicationmanager/application-features/doc/images/application-features.png
new file mode 100644
index 00000000..6d28e91f
--- /dev/null
+++ b/examples/applicationmanager/application-features/doc/images/application-features.png
Binary files differ
diff --git a/examples/applicationmanager/application-features/doc/src/application-features.qdoc b/examples/applicationmanager/application-features/doc/src/application-features.qdoc
new file mode 100644
index 00000000..f0276c2d
--- /dev/null
+++ b/examples/applicationmanager/application-features/doc/src/application-features.qdoc
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:FDL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 applicationmanager/application-features
+\title Application Features Example
+\image application-features.png
+\brief Showcases client applications with various features, including a native application.
+\ingroup applicationmanager-examples
+
+\section1 Introduction
+
+This example demonstrates how to implement some particular features you may require in an
+application, such as:
+
+\list
+ \li how to implement a nested compositor
+ \li how to simulate a crash and recover from it
+ \li how to show multiple top-level windows simultaneously
+ \li how to use the native runtime, with no QML
+
+\endlist
+
+Most of these features are only supported properly in
+\l{Single-Process vs. Multi-Process Mode}{multi-process mode}.
+
+\note This example focuses on the application (client) side. The \l{The System UI}{System UI}
+(compositor/server) is based on the \l{Desktop System UI Example} with some modifications. Refer
+to that example for more details on how to implement a System UI.
+
+\section2 Nested Compositor
+
+The nested compositor application shows how to implement a Wayland compositor inside an application
+(Wayland client) window. The compositor is implemented in pure QML and kept to a minimum. To
+display Wayland clients within this compositor, you need to set the \c WAYLAND_DISPLAY environment
+variable appropriately.
+
+To start a client with this environment variable set via command line:
+
+\badcode
+WAYLAND_DISPLAY=qtam-wayland-nested qmlscene client.qml -platform wayland
+\endcode
+
+This command only works in multi-process mode, since the nested compositor needs a real window as
+its root element.
+
+The QML code for the nested compositor application is as follows:
+
+\quotefromfile applicationmanager/application-features/apps/compositor/compositor.qml
+\skipto import QtQuick 2.11
+\printuntil /^\}/
+
+\section2 Crash Simulation and Recovery
+
+This application provides various means to force a crash in an application, such as a segmentation
+fault. It utilizes a QML plugin implemented in C++, to provide the \c Terminator QML type to
+trigger crashes. The application manager then prints the cause of the crash and related
+information, like a backtrace. The System UI implements a basic form of crash recovery: restarting
+the application.
+
+This application only works on multi-process mode. In single-process mode a crash affects the entire
+program (the System UI).
+
+The QML code for the crash simulation and recovery application is as follows:
+
+\quotefromfile applicationmanager/application-features/apps/crash/crashapp.qml
+\skipto import QtQuick 2.11
+\printuntil case "gracefully": Terminator.exitGracefully(); break;
+\printuntil /^\}/
+
+\section2 Two Top-Level Windows
+
+This application illustrates how you can display multiple top-level windows by having a QtObject
+as the application's root element.
+
+The QML code for the two top-level windows application is as follows:
+
+\quotefromfile applicationmanager/application-features/apps/twins/twins.qml
+\skipto import QtQuick 2.11
+\printuntil Component.onCompleted: setWindowProperty("type", "pop-up");
+\printuntil /^\}/
+
+\section2 Native Widgets
+
+This application is based on \l{QWidget}s. Compared to the other applications in this example,
+which are QML applications, this one uses the native runtime. Consequently, the application's entry
+point isn't a \c{main.qml} file, but an executable. This application is a basic application that
+still adheres to this particular System UI. It's meant to illustrate the concept: the System UI
+needs a \c type window property to differentiate between normal windows and popups.
+
+This application only works in multi-process mode, as application processes cannot be started in
+single-process mode.
+
+The C++ code for the native widgets application is as follows:
+
+\quotefromfile applicationmanager/application-features/native/widgets/main.cpp
+\skipto #include <QApplication>
+\printuntil /^\}/
+
+\section1 Code Structure
+
+Compared to the other Qt Application Manager Examples, which are purely based on QML, this example
+requires you to build it explicitly. The code is structured in a way where the resulting application
+folders only contain the artifacts necessary to run the application. Consequently, you can package
+these applications and install them as well.
+
+To build Qt Application Manager including its examples, you need to pass \c qmake the
+\c{-config enable-examples} parameter For more details, see \l{build}{Build}.
+*/
diff --git a/examples/applicationmanager/application-features/imports/imports.pro b/examples/applicationmanager/application-features/imports/imports.pro
new file mode 100644
index 00000000..4f736dac
--- /dev/null
+++ b/examples/applicationmanager/application-features/imports/imports.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = terminator2
diff --git a/examples/applicationmanager/application-features/imports/terminator2/qmldir b/examples/applicationmanager/application-features/imports/terminator2/qmldir
new file mode 100644
index 00000000..ac15a495
--- /dev/null
+++ b/examples/applicationmanager/application-features/imports/terminator2/qmldir
@@ -0,0 +1,2 @@
+module Terminator
+plugin terminator2plugin
diff --git a/examples/applicationmanager/application-features/imports/terminator2/qmlterminator2.cpp b/examples/applicationmanager/application-features/imports/terminator2/qmlterminator2.cpp
new file mode 100644
index 00000000..ae03e600
--- /dev/null
+++ b/examples/applicationmanager/application-features/imports/terminator2/qmlterminator2.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 <QQmlEngine>
+#include <QJSEngine>
+
+#include "qmlterminator2.h"
+
+#include <signal.h>
+
+
+static QObject *terminator_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
+{
+ Q_UNUSED(scriptEngine)
+ return new Terminator(engine);
+}
+
+void TerminatorPlugin::registerTypes(const char *uri)
+{
+ qmlRegisterSingletonType<Terminator>(uri, 2, 0, "Terminator", terminator_provider);
+}
+
+
+void Terminator::accessIllegalMemory() const
+{
+ *(int*)1 = 42;
+}
+
+void Terminator::accessIllegalMemoryInThread()
+{
+ TerminatorThread *t = new TerminatorThread(this);
+ t->start();
+}
+
+void Terminator::forceStackOverflow() const
+{
+ static constexpr int len = 100000;
+ volatile char buf[len];
+ buf[len-1] = 42;
+ if (buf[len-1] == 42)
+ forceStackOverflow();
+}
+
+void Terminator::divideByZero() const
+{
+ int d = 0;
+ volatile int x = 42 / d;
+ Q_UNUSED(x)
+}
+
+void Terminator::abort() const
+{
+ ::abort();
+}
+
+void Terminator::raise(int sig) const
+{
+ ::raise(sig);
+}
+
+void Terminator::throwUnhandledException() const
+{
+ throw 42;
+}
+
+void Terminator::exitGracefully() const
+{
+ exit(5);
+}
+
+
+TerminatorThread::TerminatorThread(Terminator *parent)
+ : QThread(parent), m_terminator(parent)
+{
+}
+
+void TerminatorThread::run()
+{
+ m_terminator->accessIllegalMemory();
+}
diff --git a/examples/applicationmanager/application-features/imports/terminator2/qmlterminator2.h b/examples/applicationmanager/application-features/imports/terminator2/qmlterminator2.h
new file mode 100644
index 00000000..5d59d6ea
--- /dev/null
+++ b/examples/applicationmanager/application-features/imports/terminator2/qmlterminator2.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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$
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QQmlExtensionPlugin>
+#include <QThread>
+
+
+class TerminatorPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
+
+public:
+ void registerTypes(const char *uri) override;
+};
+
+
+class Terminator : public QObject
+{
+ Q_OBJECT
+
+public:
+ Terminator(QObject *parent) : QObject(parent) {}
+
+ Q_INVOKABLE void accessIllegalMemory() const;
+ Q_INVOKABLE void accessIllegalMemoryInThread();
+ Q_INVOKABLE void forceStackOverflow() const;
+ Q_INVOKABLE void divideByZero() const;
+ Q_INVOKABLE void abort() const;
+ Q_INVOKABLE void raise(int sig) const;
+ Q_INVOKABLE void throwUnhandledException() const;
+ Q_INVOKABLE void exitGracefully() const;
+};
+
+
+class TerminatorThread : public QThread
+{
+ Q_OBJECT
+
+public:
+ explicit TerminatorThread(Terminator *parent);
+
+private:
+ void run() override;
+ Terminator *m_terminator;
+};
diff --git a/examples/applicationmanager/application-features/imports/terminator2/terminator2.pro b/examples/applicationmanager/application-features/imports/terminator2/terminator2.pro
new file mode 100644
index 00000000..c68900df
--- /dev/null
+++ b/examples/applicationmanager/application-features/imports/terminator2/terminator2.pro
@@ -0,0 +1,21 @@
+TEMPLATE = lib
+CONFIG += plugin exceptions install_ok
+QT += qml quick
+
+TARGET = $$qtLibraryTarget(terminator2plugin)
+
+HEADERS += qmlterminator2.h
+SOURCES += qmlterminator2.cpp
+
+OTHER_FILES += qmldir
+
+DESTDIR = $$OUT_PWD/../../apps/crash/Terminator
+
+qmldir_copy.files = $$PWD/qmldir
+qmldir_copy.path = $$DESTDIR
+COPIES += qmldir_copy
+
+target.path = $$[QT_INSTALL_EXAMPLES]/applicationmanager/application-features/apps/crash/Terminator
+qmldir.files = $$PWD/qmldir
+qmldir.path = $${target.path}
+INSTALLS += target qmldir
diff --git a/examples/applicationmanager/application-features/native/native.pro b/examples/applicationmanager/application-features/native/native.pro
new file mode 100644
index 00000000..df48bdc9
--- /dev/null
+++ b/examples/applicationmanager/application-features/native/native.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+qtHaveModule(waylandclient) {
+ SUBDIRS = widgets
+}
diff --git a/examples/applicationmanager/application-features/native/widgets/main.cpp b/examples/applicationmanager/application-features/native/widgets/main.cpp
new file mode 100644
index 00000000..4c1c0914
--- /dev/null
+++ b/examples/applicationmanager/application-features/native/widgets/main.cpp
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 <QApplication>
+#include <QPushButton>
+#include <QDialog>
+#include <QVBoxLayout>
+
+#include "launchermain.h"
+#include "logging.h"
+#include "dbusapplicationinterface.h"
+#include "dbusnotification.h"
+
+
+int main(int argc, char *argv[])
+{
+ QtAM::Logging::initialize(argc, argv);
+ QtAM::Logging::setApplicationId("widgets");
+
+ QtAM::LauncherMain::initialize();
+ QApplication app(argc, argv);
+ QtAM::LauncherMain launcher;
+
+ launcher.registerWaylandExtensions();
+ launcher.loadConfiguration();
+ launcher.setupLogging(false, launcher.loggingRules(), QString(), launcher.useAMConsoleLogger());
+ launcher.setupDBusConnections();
+
+ QWidget window;
+ QVBoxLayout layout(&window);
+
+ // Popup using application manager window property
+ QPushButton button1(QStringLiteral("Click to open/close a popup"));
+ button1.setStyleSheet(QStringLiteral("QPushButton { background-color : limegreen; font-size: 36px; }"));
+ layout.addWidget(&button1);
+
+ QDialog *popup1 = new QDialog(&window);
+ (new QPushButton(QStringLiteral("I'm a popup!"), popup1))->resize(340, 140);
+ popup1->setStyleSheet(QStringLiteral("QPushButton { background-color : limegreen; color : white; font-size: 24px; }"));
+ QObject::connect(&button1, &QPushButton::clicked, [&popup1, &launcher] () {
+ popup1->setVisible(!popup1->isVisible());
+ launcher.setWindowProperty(popup1->windowHandle(), "type", QStringLiteral("pop-up"));
+ });
+
+ // Notification
+ QPushButton button2(QStringLiteral("Click to open a notification"));
+ button2.setStyleSheet(QStringLiteral("QPushButton { background-color : darkgrey; font-size: 36px; }"));
+ layout.addWidget(&button2);
+
+ QtAM::DBusNotification *notification = QtAM::DBusNotification::create(&app);
+ notification->setSummary(QStringLiteral("I'm a notification"));
+ QObject::connect(&button2, &QPushButton::clicked, notification, &QtAM::DBusNotification::show);
+
+ // Application interface for handling quit
+ QtAM::DBusApplicationInterface iface(launcher.p2pDBusName(), launcher.notificationDBusName());
+ iface.initialize();
+ QObject::connect(&iface, &QtAM::DBusApplicationInterface::quit, [&iface] () {
+ iface.acknowledgeQuit();
+ });
+
+ app.processEvents();
+ window.showNormal();
+
+ return app.exec();
+}
diff --git a/examples/applicationmanager/application-features/native/widgets/widgets.pro b/examples/applicationmanager/application-features/native/widgets/widgets.pro
new file mode 100644
index 00000000..bf5ef1d4
--- /dev/null
+++ b/examples/applicationmanager/application-features/native/widgets/widgets.pro
@@ -0,0 +1,10 @@
+TEMPLATE = app
+CONFIG += install_ok
+QT += widgets appman_launcher-private appman_common-private
+
+SOURCES = main.cpp
+
+DESTDIR = $$OUT_PWD/../../apps/widgets
+
+target.path = $$[QT_INSTALL_EXAMPLES]/applicationmanager/application-features/apps/widgets
+INSTALLS += target
diff --git a/examples/applicationmanager/application-features/system-ui/grab.png b/examples/applicationmanager/application-features/system-ui/grab.png
new file mode 100644
index 00000000..641c6960
--- /dev/null
+++ b/examples/applicationmanager/application-features/system-ui/grab.png
Binary files differ
diff --git a/examples/applicationmanager/application-features/system-ui/main.qml b/examples/applicationmanager/application-features/system-ui/main.qml
new file mode 100644
index 00000000..83c1c408
--- /dev/null
+++ b/examples/applicationmanager/application-features/system-ui/main.qml
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+
+import QtQuick 2.11
+import QtQuick.Window 2.11
+import QtApplicationManager.SystemUI 2.0
+
+Window {
+ title: "Application Features - QtApplicationManager Example"
+ width: 1280
+ height: 800
+ color: "whitesmoke"
+
+ Text {
+ anchors.bottom: parent.bottom
+ text: (ApplicationManager.singleProcess ? "Single" : "Multi") + "-Process Mode"
+ }
+
+ Column {
+ z: 9998
+ Repeater {
+ model: ApplicationManager
+
+ Image {
+ source: icon
+ opacity: isRunning ? 0.3 : 1.0
+
+ Rectangle {
+ x: 96; y: 38
+ width: appid.width; height: appid.height
+ color: "whitesmoke"
+ visible: imouse.containsMouse
+
+ Text {
+ id: appid
+ text: application.name("en")
+ }
+ }
+
+ MouseArea {
+ id: imouse
+ anchors.fill: parent
+ hoverEnabled: true
+ onClicked: isRunning ? application.stop() : application.start();
+ }
+ }
+ }
+ }
+
+ Repeater {
+ model: ListModel { id: topLevelWindowsModel }
+
+ delegate: Rectangle {
+ id: chrome
+ width: draggrab.x + 10; height: draggrab.y + 10
+ color: "transparent"
+ border.width: 3
+ border.color: "grey"
+ z: model.index
+
+ Image {
+ id: draggrab
+ x: 710; y: 530
+ source: "grab.png"
+ visible: dragarea.containsMouse
+ }
+
+ MouseArea {
+ id: dragarea
+ anchors.fill: draggrab
+ hoverEnabled: true
+ drag.target: draggrab
+ drag.minimumX: 230
+ drag.minimumY: 170
+ }
+
+ Rectangle {
+ height: 25
+ width: parent.width
+ color: "grey"
+
+ Text {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: model.window.application ? model.window.application.name("en") : 'External Application'
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ drag.target: chrome
+ onPressed: topLevelWindowsModel.move(model.index, topLevelWindowsModel.count - 1, 1);
+ }
+
+ Rectangle {
+ width: 25; height: 25
+ color: "chocolate"
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: model.window.close();
+ }
+ }
+ }
+
+ WindowItem {
+ anchors.fill: parent
+ anchors.margins: 3
+ anchors.topMargin: 25
+ window: model.window
+
+ Connections {
+ target: window
+ onContentStateChanged: {
+ if (window.contentState === WindowObject.NoSurface)
+ topLevelWindowsModel.remove(model.index, 1);
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ x = 200 + model.index * 50;
+ y = 20 + model.index * 30;
+ }
+ }
+ }
+
+ Repeater {
+ model: ListModel { id: popupsModel }
+ delegate: WindowItem {
+ z: 9999 + model.index
+ anchors.centerIn: parent
+ window: model.window
+ Connections {
+ target: model.window
+ onContentStateChanged: {
+ if (model.window.contentState === WindowObject.NoSurface)
+ popupsModel.remove(model.index, 1);
+ }
+ }
+ }
+ }
+
+ Text {
+ z: 9999
+ font.pixelSize: 46
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: NotificationManager.count > 0 ? NotificationManager.get(0).summary : ""
+ }
+
+ Connections {
+ target: WindowManager
+ onWindowAdded: {
+ var model = window.windowProperty("type") === "pop-up" ? popupsModel : topLevelWindowsModel;
+ model.append({"window":window});
+ }
+ }
+
+ Connections {
+ target: ApplicationManager
+ onApplicationRunStateChanged: {
+ if (runState === Am.NotRunning
+ && ApplicationManager.application(id).lastExitStatus === Am.CrashExit) {
+ ApplicationManager.startApplication(id);
+ }
+ }
+ }
+}
diff --git a/examples/applicationmanager/application-features/ui.pro b/examples/applicationmanager/application-features/ui.pro
new file mode 100644
index 00000000..7d9e85e6
--- /dev/null
+++ b/examples/applicationmanager/application-features/ui.pro
@@ -0,0 +1,36 @@
+TEMPLATE = app
+CONFIG += am-systemui
+
+OTHER_FILES += \
+ am-config.yaml \
+ application-features.qmlproject \
+ doc/src/*.qdoc \
+ doc/images/*.png \
+ system-ui/*.qml \
+ system-ui/*.png \
+ apps/compositor/*.yaml \
+ apps/compositor/*.qml \
+ apps/compositor/*.png \
+ apps/crash/*.yaml \
+ apps/crash/*.qml \
+ apps/crash/*.png \
+ apps/twins/*.yaml \
+ apps/twins/*.qml \
+ apps/twins/*.png \
+ apps/widgets/*.yaml \
+ apps/widgets/*.png
+
+target.path = $$[QT_INSTALL_EXAMPLES]/applicationmanager/application-features
+INSTALLS += target
+
+AM_COPY_DIRECTORIES += apps system-ui
+AM_COPY_FILES += am-config.yaml
+
+prefix_build:tpath = $$target.path
+else:tpath = $$OUT_PWD
+
+AM_DEFAULT_ARGS = -c $$tpath/am-config.yaml
+
+example_sources.path = $$target.path
+example_sources.files = $$AM_COPY_FILES $$AM_COPY_DIRECTORIES doc
+INSTALLS += example_sources
diff --git a/examples/applicationmanager/applicationmanager.pro b/examples/applicationmanager/applicationmanager.pro
index 49cc2c82..6ea4e083 100644
--- a/examples/applicationmanager/applicationmanager.pro
+++ b/examples/applicationmanager/applicationmanager.pro
@@ -9,6 +9,7 @@ SUBDIRS = \
frame-timer \
hello-world \
minidesk \
+ application-features \
multi-views \
process-status \
startup-plugin \
diff --git a/examples/applicationmanager/custom-appman/custom-appman.cpp b/examples/applicationmanager/custom-appman/custom-appman.cpp
index 85f5d87a..c02e91c0 100644
--- a/examples/applicationmanager/custom-appman/custom-appman.cpp
+++ b/examples/applicationmanager/custom-appman/custom-appman.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
@@ -54,9 +55,9 @@
#include <QtAppManCommon/global.h>
#include <QtAppManCommon/logging.h>
#include <QtAppManMain/main.h>
-#include <QtAppManMain/defaultconfiguration.h>
-#include <QtAppManPackage/package.h>
-#include <QtAppManInstaller/sudo.h>
+#include <QtAppManMain/configuration.h>
+#include <QtAppManPackage/packageutilities.h>
+#include <QtAppManManager/sudo.h>
QT_USE_NAMESPACE_AM
@@ -67,13 +68,13 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
QCoreApplication::setApplicationVersion("0.1");
Logging::initialize(argc, argv);
- Package::ensureCorrectLocale();
+ PackageUtilities::ensureCorrectLocale();
Sudo::forkServer(Sudo::DropPrivilegesPermanently);
try {
Main a(argc, argv);
- DefaultConfiguration cfg;
+ Configuration cfg;
cfg.parse();
a.setup(&cfg);
diff --git a/examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc b/examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc
index 2f819c32..4edcc3fb 100644
--- a/examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc
+++ b/examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
@@ -69,7 +69,7 @@ Generally, it's a good idea to set an application name and version.
We want the application manager's logging part to be initialized as early as possible, especially
when we are dealing with DLT logging.
-\printline Package::ensure
+\printline PackageUtilities::ensure
If you are using the application manager's installer part, this function needs to be called
\e before the QApplication constructor to make sure that your C locale is a UTF-8 variant. This is
diff --git a/examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.qml b/examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.qml
index 823ce505..9d3c6107 100644
--- a/examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.qml
+++ b/examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.qml b/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.qml
index 4b5892b0..42a2cfab 100644
--- a/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.qml
+++ b/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/frame-timer/doc/src/frame-timer-example.qdoc b/examples/applicationmanager/frame-timer/doc/src/frame-timer-example.qdoc
index 2397f508..e0939058 100644
--- a/examples/applicationmanager/frame-timer/doc/src/frame-timer-example.qdoc
+++ b/examples/applicationmanager/frame-timer/doc/src/frame-timer-example.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/frame-timer/frame-timer.pro b/examples/applicationmanager/frame-timer/frame-timer.pro
index db6258ef..f3870d03 100644
--- a/examples/applicationmanager/frame-timer/frame-timer.pro
+++ b/examples/applicationmanager/frame-timer/frame-timer.pro
@@ -22,7 +22,7 @@ AM_COPY_FILES += am-config.yaml
prefix_build:tpath = $$target.path
else:tpath = $$_PRO_FILE_PWD_
-AM_DEFAULT_ARGS = -c $$tpath/am-config.yaml --verbose -r
+AM_DEFAULT_ARGS = -c $$tpath/am-config.yaml --verbose
example_sources.path = $$target.path
example_sources.files = $$AM_COPY_FILES $$AM_COPY_DIRECTORIES
diff --git a/examples/applicationmanager/frame-timer/system-ui/main.qml b/examples/applicationmanager/frame-timer/system-ui/main.qml
index 1055843d..b95cec1d 100644
--- a/examples/applicationmanager/frame-timer/system-ui/main.qml
+++ b/examples/applicationmanager/frame-timer/system-ui/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/hello-world/apps/hello-world.blue/main.qml b/examples/applicationmanager/hello-world/apps/hello-world.blue/main.qml
index 8dd0a2a4..a2ba7929 100644
--- a/examples/applicationmanager/hello-world/apps/hello-world.blue/main.qml
+++ b/examples/applicationmanager/hello-world/apps/hello-world.blue/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/hello-world/apps/hello-world.green/main.qml b/examples/applicationmanager/hello-world/apps/hello-world.green/main.qml
index e2bbfd41..6fda63f7 100644
--- a/examples/applicationmanager/hello-world/apps/hello-world.green/main.qml
+++ b/examples/applicationmanager/hello-world/apps/hello-world.green/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/hello-world/apps/hello-world.red/main.qml b/examples/applicationmanager/hello-world/apps/hello-world.red/main.qml
index 944ee7db..fd04b159 100644
--- a/examples/applicationmanager/hello-world/apps/hello-world.red/main.qml
+++ b/examples/applicationmanager/hello-world/apps/hello-world.red/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/hello-world/doc/src/hello-world.qdoc b/examples/applicationmanager/hello-world/doc/src/hello-world.qdoc
index e3978de5..404efff9 100644
--- a/examples/applicationmanager/hello-world/doc/src/hello-world.qdoc
+++ b/examples/applicationmanager/hello-world/doc/src/hello-world.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
@@ -158,7 +158,7 @@ an ApplicationManagerWindow, provided by the \c QtApplicationManager.Application
\section2 Application Metadata
The \c info.yaml file contains the metadata about an application. It starts with some boilerplate
-desribing that this file contains Qt Application Manager application metadata.
+describing that this file contains Qt Application Manager application metadata.
\quotefromfile applicationmanager/hello-world/apps/hello-world.blue/info.yaml
\printuntil --
diff --git a/examples/applicationmanager/hello-world/system-ui.qml b/examples/applicationmanager/hello-world/system-ui.qml
index 2d5aaa11..95f3edb8 100644
--- a/examples/applicationmanager/hello-world/system-ui.qml
+++ b/examples/applicationmanager/hello-world/system-ui.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/intents/apps/intents.blue/main.qml b/examples/applicationmanager/intents/apps/intents.blue/main.qml
index fe549f88..89321457 100644
--- a/examples/applicationmanager/intents/apps/intents.blue/main.qml
+++ b/examples/applicationmanager/intents/apps/intents.blue/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/intents/apps/intents.green/main.qml b/examples/applicationmanager/intents/apps/intents.green/main.qml
index fe549f88..89321457 100644
--- a/examples/applicationmanager/intents/apps/intents.green/main.qml
+++ b/examples/applicationmanager/intents/apps/intents.green/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/intents/apps/intents.red/main.qml b/examples/applicationmanager/intents/apps/intents.red/main.qml
index 3d6b070d..f9c3998a 100644
--- a/examples/applicationmanager/intents/apps/intents.red/main.qml
+++ b/examples/applicationmanager/intents/apps/intents.red/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/intents/doc/src/intents.qdoc b/examples/applicationmanager/intents/doc/src/intents.qdoc
index 07c062b3..f1da854a 100644
--- a/examples/applicationmanager/intents/doc/src/intents.qdoc
+++ b/examples/applicationmanager/intents/doc/src/intents.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/intents/shared/IntentsApplicationWindow.qml b/examples/applicationmanager/intents/shared/IntentsApplicationWindow.qml
index 4f56b576..ee58b1c2 100644
--- a/examples/applicationmanager/intents/shared/IntentsApplicationWindow.qml
+++ b/examples/applicationmanager/intents/shared/IntentsApplicationWindow.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/intents/shared/IntentsUIPage.qml b/examples/applicationmanager/intents/shared/IntentsUIPage.qml
index ccf5534f..0420a089 100644
--- a/examples/applicationmanager/intents/shared/IntentsUIPage.qml
+++ b/examples/applicationmanager/intents/shared/IntentsUIPage.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/intents/system-ui.qml b/examples/applicationmanager/intents/system-ui.qml
index 07efbcf2..e3198f80 100644
--- a/examples/applicationmanager/intents/system-ui.qml
+++ b/examples/applicationmanager/intents/system-ui.qml
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
@@ -204,8 +205,8 @@ Item {
delegate: ItemDelegate {
property ApplicationObject application: ApplicationManager.application(modelData.applicationId)
width: parent.width
- text: application.name("en") + " (" + modelData.applicationId + ")"
- icon.source: application.icon
+ text: modelData.name + " (" + modelData.applicationId + ")"
+ icon.source: modelData.icon
icon.color: "transparent"
highlighted: ListView.isCurrentItem
onClicked: { handlingApplications.currentIndex = index }
diff --git a/examples/applicationmanager/minidesk/am-config.yaml b/examples/applicationmanager/minidesk/am-config.yaml
index 376a2265..a557944d 100644
--- a/examples/applicationmanager/minidesk/am-config.yaml
+++ b/examples/applicationmanager/minidesk/am-config.yaml
@@ -1,16 +1,10 @@
formatVersion: 1
formatType: am-configuration
---
-installationLocations:
-- id: "internal-0"
- installationPath: "/tmp/minidesk/apps"
- documentPath: "/tmp/minidesk/docs"
- mountPoint: "/tmp"
- isDefault: true
-
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/apps"
- installedAppsManifestDir: "/tmp/minidesk/manifests"
+ installationDir: "/tmp/minidesk/apps"
+ documentDir: "/tmp/minidesk/docs"
logging:
rules:
diff --git a/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/app1.qml b/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/app1.qml
index ae005f47..62aa661a 100644
--- a/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/app1.qml
+++ b/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/app1.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
@@ -56,12 +56,12 @@ import QtApplicationManager.Application 2.0
ApplicationManagerWindow {
id: root
- color: "peachpuff"
+ color: "lightgrey"
Rectangle {
anchors.centerIn: parent
width: 180; height: 180; radius: width/4
- color: "peru"
+ color: "lightsteelblue"
Image {
source: ApplicationInterface.icon
@@ -90,7 +90,7 @@ ApplicationManagerWindow {
ApplicationManagerWindow {
id: popUp
visible: false
- color: "lightcoral"
+ color: "orangered"
Text {
anchors.centerIn: parent
diff --git a/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/icon.png b/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/icon.png
index adb840ce..35a54600 100644
--- a/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/icon.png
+++ b/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/icon.png
Binary files differ
diff --git a/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/info.yaml b/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/info.yaml
index 953e852f..6b2efc9b 100644
--- a/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/info.yaml
+++ b/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/info.yaml
@@ -1,9 +1,11 @@
formatVersion: 1
-formatType: am-application
+formatType: am-package
---
-id: 'tld.minidesk.app1'
-icon: 'icon.png'
-code: 'app1.qml'
-runtime: 'qml'
+id: 'tld.minidesk.app1'
+icon: 'icon.png'
name:
en: 'App1'
+applications:
+ - id: 'tld.minidesk.app1'
+ code: 'app1.qml'
+ runtime: 'qml'
diff --git a/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/app2.qml b/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/app2.qml
index ae4db3a3..c4bef427 100644
--- a/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/app2.qml
+++ b/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/app2.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
@@ -55,7 +55,7 @@ import QtQuick 2.4
import QtApplicationManager.Application 2.0
ApplicationManagerWindow {
- color: ApplicationInterface.systemProperties.light ? "peachpuff" : "black"
+ color: ApplicationInterface.systemProperties.light ? "#B0808080" : "black"
Image {
anchors.centerIn: parent
diff --git a/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/icon.png b/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/icon.png
index 3f8caa42..9c1d6cf2 100644
--- a/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/icon.png
+++ b/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/icon.png
Binary files differ
diff --git a/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/info.yaml b/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/info.yaml
index 65759aa8..140955eb 100644
--- a/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/info.yaml
+++ b/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/info.yaml
@@ -1,9 +1,11 @@
formatVersion: 1
-formatType: am-application
+formatType: am-package
---
-id: 'tld.minidesk.app2'
-icon: 'icon.png'
-code: 'app2.qml'
-runtime: 'qml'
+id: 'tld.minidesk.app2'
+icon: 'icon.png'
name:
en: 'App2'
+applications:
+ - id: 'tld.minidesk.app2'
+ code: 'app2.qml'
+ runtime: 'qml'
diff --git a/examples/applicationmanager/minidesk/doc/images/minidesk.png b/examples/applicationmanager/minidesk/doc/images/minidesk.png
index 66a545c9..edbe0783 100644
--- a/examples/applicationmanager/minidesk/doc/images/minidesk.png
+++ b/examples/applicationmanager/minidesk/doc/images/minidesk.png
Binary files differ
diff --git a/examples/applicationmanager/minidesk/doc/src/minidesk.qdoc b/examples/applicationmanager/minidesk/doc/src/minidesk.qdoc
index e44e5854..ea1e7be0 100644
--- a/examples/applicationmanager/minidesk/doc/src/minidesk.qdoc
+++ b/examples/applicationmanager/minidesk/doc/src/minidesk.qdoc
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
@@ -66,7 +67,7 @@ generic Inter-Process Communication (IPC).
To start the example, navigate to the \c minidesk folder, and run the following command:
\badcode
-<path-to-appman-binary> -c am-config.yaml -r
+<path-to-appman-binary> -c am-config.yaml
\endcode
The \c appman binary (executable file) is usually located in the Qt installation \c bin folder.
@@ -81,11 +82,11 @@ The \c appman binary (executable file) is usually located in the Qt installation
\dots
The \l{QtApplicationManager.SystemUI} module has to be imported to access the application manager
-APIs. The System UI window has a fixed size and linen background color. Instead of a \l{Rectangle},
-the root element could also be a \l{Window}. On top of the background, we display a
-\c Readme element with information on the
-features available. At the bottom left there is a textual indication for whether the
-application manager runs in single-process or multi-process mode.
+APIs. The System UI window has a fixed size and "whitesmoke" background color. Instead of a
+\l{Window}, the root element could also be a regular item, like a \l{Rectangle}. The application
+manager would wrap it in a window for you. On top of the background, we display a \c Readme element
+with information on the features available. At the bottom left there is a textual indication for
+whether the application manager runs in single-process or multi-process mode.
\section2 Launcher
@@ -114,8 +115,8 @@ WindowManager. The code that populates the window role of this ListModel is show
now let's focus on what this Repeater's delegate consists of:
\list
- \li A fixed size window container \l{Rectangle} in "tan" color. The location depends on the
- \c model.index, hence each application window has a different initial location.
+ \li A mostly transparent background \l{Image}. The location depends on the \c model.index,
+ hence each application window has a different initial location.
\li The name of the application that created that window, prefixed with "Decoration" on top.
This name is from the related ApplicationObject, defined in the application's
\l{Manifest Definition}{info.yaml} file.
@@ -205,7 +206,7 @@ the \l {WindowManager::windowAdded}{onWindowAdded} handler is invoked.
Only App1's "pop-up" ApplicationManagerWindow has the user-defined \c type property set. Such a
window is placed in the \c popUpContainer WindowItem. All other windows don't have a \c type
-property; they are added to the \c topLevelWindowsModel. This model is used in the SystemUI chrome
+property; they are added to the \c topLevelWindowsModel. This model is used in the System UI chrome
Repeater above. Consequently, the \l {WindowObject}{window} object passed as an argument to
\l {WindowManager::windowAdded}{onWindowAdded} is set as the
\l{WindowItem::window}{window} property of the WindowItem (within the Repeater's delegate).
@@ -215,7 +216,7 @@ will also be displayed since in the configuration file, "\c flags/noSecurity: \c
instance in KDE's Calculator:
\badcode
-$ QT_WAYLAND_DISABLE_WINDOWDECORATION=1 QT_WAYLAND_SHELL_INTEGRATION=xdg-shell-v5 kcalc -platform wayland
+$ QT_WAYLAND_DISABLE_WINDOWDECORATION=1 WAYLAND_DISPLAY=qtam-wayland-0 kcalc -platform wayland
\endcode
\section2 Inter-Process Communication (IPC) Extension
diff --git a/examples/applicationmanager/minidesk/system-ui/Readme.qml b/examples/applicationmanager/minidesk/system-ui/Readme.qml
index 6565df71..65643913 100644
--- a/examples/applicationmanager/minidesk/system-ui/Readme.qml
+++ b/examples/applicationmanager/minidesk/system-ui/Readme.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/minidesk/system-ui/chrome-bg.png b/examples/applicationmanager/minidesk/system-ui/chrome-bg.png
new file mode 100644
index 00000000..0a6618c4
--- /dev/null
+++ b/examples/applicationmanager/minidesk/system-ui/chrome-bg.png
Binary files differ
diff --git a/examples/applicationmanager/minidesk/system-ui/main.qml b/examples/applicationmanager/minidesk/system-ui/main.qml
index 43265237..577599a2 100644
--- a/examples/applicationmanager/minidesk/system-ui/main.qml
+++ b/examples/applicationmanager/minidesk/system-ui/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
@@ -51,13 +51,15 @@
**
****************************************************************************/
-import QtQuick 2.4
+import QtQuick 2.11
+import QtQuick.Window 2.11
import QtApplicationManager.SystemUI 2.0
-Rectangle {
+Window {
+ title: "Minidesk - QtApplicationManager Example"
width: 1024
height: 640
- color: "linen"
+ color: "whitesmoke"
Readme {}
@@ -87,10 +89,9 @@ Rectangle {
Repeater {
model: ListModel { id: topLevelWindowsModel }
- delegate: Rectangle {
- width: 400; height: 320
+ delegate: Image {
+ source: "chrome-bg.png"
z: model.index
- color: "tan"
Text {
anchors.horizontalCenter: parent.horizontalCenter
diff --git a/examples/applicationmanager/multi-views/apps/tld.multi-views.app/app1.qml b/examples/applicationmanager/multi-views/apps/tld.multi-views.app/app1.qml
index e5e3f6e8..dd8c7bbd 100644
--- a/examples/applicationmanager/multi-views/apps/tld.multi-views.app/app1.qml
+++ b/examples/applicationmanager/multi-views/apps/tld.multi-views.app/app1.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/multi-views/doc/src/multi-views.qdoc b/examples/applicationmanager/multi-views/doc/src/multi-views.qdoc
index 959b3dd7..7e5c6d9e 100644
--- a/examples/applicationmanager/multi-views/doc/src/multi-views.qdoc
+++ b/examples/applicationmanager/multi-views/doc/src/multi-views.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/multi-views/multi-views.pro b/examples/applicationmanager/multi-views/multi-views.pro
index 2cff5f66..cdb52da8 100644
--- a/examples/applicationmanager/multi-views/multi-views.pro
+++ b/examples/applicationmanager/multi-views/multi-views.pro
@@ -4,6 +4,8 @@ CONFIG += am-systemui
OTHER_FILES += \
am-config.yaml \
system-ui/*.qml \
+ doc/src/*.qdoc \
+ doc/images/*.png \
apps/tld.multi-views.app/*.yaml \
apps/tld.multi-views.app/*.qml \
apps/tld.multi-views.app/*.png \
@@ -17,7 +19,7 @@ AM_COPY_FILES += am-config.yaml
prefix_build:tpath = $$target.path
else:tpath = $$_PRO_FILE_PWD_
-AM_DEFAULT_ARGS = -c $$tpath/am-config.yaml --verbose -r
+AM_DEFAULT_ARGS = -c $$tpath/am-config.yaml --verbose
example_sources.path = $$target.path
example_sources.files = $$AM_COPY_FILES $$AM_COPY_DIRECTORIES
diff --git a/examples/applicationmanager/multi-views/system-ui/Readme.qml b/examples/applicationmanager/multi-views/system-ui/Readme.qml
index 23a7fb0b..ab201033 100644
--- a/examples/applicationmanager/multi-views/system-ui/Readme.qml
+++ b/examples/applicationmanager/multi-views/system-ui/Readme.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/multi-views/system-ui/main.qml b/examples/applicationmanager/multi-views/system-ui/main.qml
index 55f48188..b3ee5309 100644
--- a/examples/applicationmanager/multi-views/system-ui/main.qml
+++ b/examples/applicationmanager/multi-views/system-ui/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/process-status/apps/process-status.cpu-hog/main.qml b/examples/applicationmanager/process-status/apps/process-status.cpu-hog/main.qml
index baed4f24..4aa746bd 100644
--- a/examples/applicationmanager/process-status/apps/process-status.cpu-hog/main.qml
+++ b/examples/applicationmanager/process-status/apps/process-status.cpu-hog/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/process-status/apps/process-status.mem-hog/main.qml b/examples/applicationmanager/process-status/apps/process-status.mem-hog/main.qml
index 9a77bcd4..b899ea96 100644
--- a/examples/applicationmanager/process-status/apps/process-status.mem-hog/main.qml
+++ b/examples/applicationmanager/process-status/apps/process-status.mem-hog/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/process-status/apps/process-status.slim/main.qml b/examples/applicationmanager/process-status/apps/process-status.slim/main.qml
index 82de9abe..89a51cd8 100644
--- a/examples/applicationmanager/process-status/apps/process-status.slim/main.qml
+++ b/examples/applicationmanager/process-status/apps/process-status.slim/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/process-status/doc/src/process-status-example.qdoc b/examples/applicationmanager/process-status/doc/src/process-status-example.qdoc
index 5d012ac2..1bafdbf5 100644
--- a/examples/applicationmanager/process-status/doc/src/process-status-example.qdoc
+++ b/examples/applicationmanager/process-status/doc/src/process-status-example.qdoc
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/process-status/process-status.pro b/examples/applicationmanager/process-status/process-status.pro
index ac1576c6..3c96e909 100644
--- a/examples/applicationmanager/process-status/process-status.pro
+++ b/examples/applicationmanager/process-status/process-status.pro
@@ -25,7 +25,7 @@ AM_COPY_FILES += am-config.yaml
prefix_build:tpath = $$target.path
else:tpath = $$_PRO_FILE_PWD_
-AM_DEFAULT_ARGS = -c $$tpath/am-config.yaml --verbose -r
+AM_DEFAULT_ARGS = -c $$tpath/am-config.yaml --verbose
example_sources.path = $$target.path
example_sources.files = $$AM_COPY_FILES $$AM_COPY_DIRECTORIES
diff --git a/examples/applicationmanager/process-status/system-ui/ApplicationDisplay.qml b/examples/applicationmanager/process-status/system-ui/ApplicationDisplay.qml
index 89fccd9e..3dabe63b 100644
--- a/examples/applicationmanager/process-status/system-ui/ApplicationDisplay.qml
+++ b/examples/applicationmanager/process-status/system-ui/ApplicationDisplay.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/process-status/system-ui/CpuGraph.qml b/examples/applicationmanager/process-status/system-ui/CpuGraph.qml
index 4ba1edd8..8cd59c72 100644
--- a/examples/applicationmanager/process-status/system-ui/CpuGraph.qml
+++ b/examples/applicationmanager/process-status/system-ui/CpuGraph.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/process-status/system-ui/MemoryText.qml b/examples/applicationmanager/process-status/system-ui/MemoryText.qml
index 6b999da1..14eaf0b1 100644
--- a/examples/applicationmanager/process-status/system-ui/MemoryText.qml
+++ b/examples/applicationmanager/process-status/system-ui/MemoryText.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/process-status/system-ui/Stats.qml b/examples/applicationmanager/process-status/system-ui/Stats.qml
index 90983804..a62b6888 100644
--- a/examples/applicationmanager/process-status/system-ui/Stats.qml
+++ b/examples/applicationmanager/process-status/system-ui/Stats.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/process-status/system-ui/main.qml b/examples/applicationmanager/process-status/system-ui/main.qml
index b342939e..57bfb463 100644
--- a/examples/applicationmanager/process-status/system-ui/main.qml
+++ b/examples/applicationmanager/process-status/system-ui/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/softwarecontainer-plugin/doc/src/softwarecontainer-plugin.qdoc b/examples/applicationmanager/softwarecontainer-plugin/doc/src/softwarecontainer-plugin.qdoc
index 8b136749..b920b4fb 100644
--- a/examples/applicationmanager/softwarecontainer-plugin/doc/src/softwarecontainer-plugin.qdoc
+++ b/examples/applicationmanager/softwarecontainer-plugin/doc/src/softwarecontainer-plugin.qdoc
@@ -3,7 +3,7 @@
** Copyright (C) 2019 Luxoft Sweden AB
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.cpp b/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.cpp
index dd27b4a3..2598f6aa 100644
--- a/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.cpp
+++ b/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.h b/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.h
index e951c55d..63ba2614 100644
--- a/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.h
+++ b/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/startup-plugin/startup-plugin.cpp b/examples/applicationmanager/startup-plugin/startup-plugin.cpp
index 0a1a9a25..3ec57bf6 100644
--- a/examples/applicationmanager/startup-plugin/startup-plugin.cpp
+++ b/examples/applicationmanager/startup-plugin/startup-plugin.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/startup-plugin/startup-plugin.h b/examples/applicationmanager/startup-plugin/startup-plugin.h
index fa62b702..f7540e96 100644
--- a/examples/applicationmanager/startup-plugin/startup-plugin.h
+++ b/examples/applicationmanager/startup-plugin/startup-plugin.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/header.BSD-QTAS b/header.BSD-QTAS
index b436e34f..00ec0076 100644
--- a/header.BSD-QTAS
+++ b/header.BSD-QTAS
@@ -1,10 +1,9 @@
/****************************************************************************
**
** Copyright (C) 2019 Luxoft Sweden AB
-** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:BSD-QTAS$
** Commercial License Usage
diff --git a/header.FDL-QTAS b/header.FDL-QTAS
index b3064965..40ff9176 100644
--- a/header.FDL-QTAS
+++ b/header.FDL-QTAS
@@ -1,10 +1,9 @@
/****************************************************************************
**
** Copyright (C) 2019 Luxoft Sweden AB
-** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the documentation of the Luxoft Application Manager.
+** This file is part of the documentation of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
diff --git a/header.GPL-EXCEPT-QTAS b/header.GPL-EXCEPT-QTAS
index 3ead040d..905efde0 100644
--- a/header.GPL-EXCEPT-QTAS
+++ b/header.GPL-EXCEPT-QTAS
@@ -1,10 +1,9 @@
/****************************************************************************
**
** Copyright (C) 2019 Luxoft Sweden AB
-** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/header.LGPL-QTAS b/header.LGPL-QTAS
index 98265f2c..31af987d 100644
--- a/header.LGPL-QTAS
+++ b/header.LGPL-QTAS
@@ -1,10 +1,9 @@
/****************************************************************************
**
** Copyright (C) 2019 Luxoft Sweden AB
-** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/qmake-features/am-qml-testcase.prf b/qmake-features/am-qml-testcase.prf
index c7f2396a..fd5d9410 100644
--- a/qmake-features/am-qml-testcase.prf
+++ b/qmake-features/am-qml-testcase.prf
@@ -40,7 +40,7 @@ prefix_build {
}
# The check command
-COMMAND += $$AM_TESTRUNNER_DIR/appman-qmltestrunner -r --no-dlt-logging
+COMMAND += $$AM_TESTRUNNER_DIR/appman-qmltestrunner --no-cache --no-dlt-logging
mac: COMMAND += --dbus=none
!multi-process: {
!build_pass:!qmltest-mode-auto:message("am-qml-testcase: forcing MODE to single-process, because application-manager is built in single-process mode")
@@ -55,10 +55,16 @@ OTHER_FILES += $$IMPORTS_DIR
# Read a config file
for(config, AM_CONFIG) {
- COMMAND += -c $$absolute_path($$config, $$_PRO_FILE_PWD_)
+ isEmpty(TESTRUN_CWD): COMMAND += -c $$absolute_path($$config, $$_PRO_FILE_PWD_)
+ else: COMMAND += -c $$config
}
OTHER_FILES += $$AM_CONFIG
+# Make AM_TESTDATA_DIR known
+!isEmpty(AM_TESTDATA_DIR) {
+ COMMAND += -o \'systemProperties: { public: { AM_TESTDATA_DIR: $$AM_TESTDATA_DIR } }\'
+}
+
!isEmpty(TESTRUN_CWD):!contains(TESTRUN_CWD, ^\\./?): \
COMMAND = cd $$shell_path($$TESTRUN_CWD) && $$eval(COMMAND)
@@ -82,8 +88,7 @@ OTHER_FILES += $$TEST_FILES
# Copy assets to build folder
for (d , DIRECTORIES) {
- win32: do_copydata.commands += $(COPY_DIR) $$shell_path($$_PRO_FILE_PWD_/$${d}) $$shell_path($$OUT_PWD/$${d}) $$escape_expand(\n\t)
- else: do_copydata.commands += $(COPY_DIR) $$shell_path($$_PRO_FILE_PWD_/$${d}) $$shell_path($$OUT_PWD) $$escape_expand(\n\t)
+ do_copydata.commands += $(COPY_DIR) $$shell_path($$_PRO_FILE_PWD_/$${d}) $$shell_path($$OUT_PWD/$${d}) $$escape_expand(\n\t)
}
for (f , FILES) {
do_copydata.commands += $(COPY) $$shell_path($$_PRO_FILE_PWD_/$${f}) $$shell_path($$OUT_PWD/$${f}) $$escape_expand(\n\t)
@@ -93,3 +98,6 @@ for (f , FILES) {
check.depends = do_copydata
QMAKE_EXTRA_TARGETS += do_copydata
}
+
+# Make sure that possible apps are in OTHER_FILES
+for (app, TEST_APPS): OTHER_FILES += apps/$${app}/*.yaml apps/$${app}/*.qml apps/$${app}/*.png
diff --git a/qmake-features/generate-resource.prf b/qmake-features/generate-resource.prf
new file mode 100644
index 00000000..54c40cea
--- /dev/null
+++ b/qmake-features/generate-resource.prf
@@ -0,0 +1,10 @@
+load(resources)
+
+generate_rcc.input = RESOURCE_SOURCE
+generate_rcc.name = RCC Generator
+generate_rcc.depend_command = $$QMAKE_RCC_DEP -list -binary ${QMAKE_FILE_IN}
+generate_rcc.CONFIG += dep_lines target_predeps no_link
+generate_rcc.output = ${QMAKE_FILE_BASE}.rcc
+generate_rcc.commands = $$QMAKE_RCC -binary ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
+
+QMAKE_EXTRA_COMPILERS += generate_rcc
diff --git a/src/application-lib/application-lib.pro b/src/application-lib/application-lib.pro
index 1f75472d..7363acc1 100644
--- a/src/application-lib/application-lib.pro
+++ b/src/application-lib/application-lib.pro
@@ -13,15 +13,21 @@ CONFIG -= create_cmake
HEADERS += \
applicationinfo.h \
- applicationscanner.h \
- yamlapplicationscanner.h \
+ packagescanner.h \
+ yamlpackagescanner.h \
installationreport.h \
applicationinterface.h \
+ intentinfo.h \
+ packageinfo.h \
+ packagedatabase.h \
SOURCES += \
applicationinfo.cpp \
- yamlapplicationscanner.cpp \
+ yamlpackagescanner.cpp \
installationreport.cpp \
applicationinterface.cpp \
+ intentinfo.cpp \
+ packageinfo.cpp \
+ packagedatabase.cpp \
load(qt_module)
diff --git a/src/application-lib/applicationinfo.cpp b/src/application-lib/applicationinfo.cpp
index f746f849..661ffa3c 100644
--- a/src/application-lib/applicationinfo.cpp
+++ b/src/application-lib/applicationinfo.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -40,82 +40,17 @@
**
****************************************************************************/
-#include <QDebug>
+#include <QDataStream>
#include <QBuffer>
#include "applicationinfo.h"
#include "exception.h"
#include "installationreport.h"
+#include "packageinfo.h"
+#include "utilities.h"
QT_BEGIN_NAMESPACE_AM
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// AbstractApplicationInfo
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool AbstractApplicationInfo::isValidApplicationId(const QString &appId, bool isAliasName, QString *errorString)
-{
- static const int maxLength = 150;
-
- try {
- if (appId.isEmpty())
- throw Exception(Error::Parse, "must not be empty");
-
- // we need to make sure that we can use the name as directory on a FAT formatted SD-card,
- // which has a 255 character path length restriction
- if (appId.length() > maxLength)
- throw Exception(Error::Parse, "the maximum length is %1 characters (found %2 characters)").arg(maxLength, appId.length());
-
- int aliasPos = -1;
-
- // aliases need to have the '@' marker
- if (isAliasName) {
- aliasPos = appId.indexOf(qL1C('@'));
- if (aliasPos < 0 || aliasPos == (appId.size() - 1))
- throw Exception(Error::Parse, "missing alias-id tag '@'");
- }
-
- // all characters need to be ASCII minus '@' and any filesystem special characters:
- bool spaceOnly = true;
- static const char forbiddenChars[] = "@<>:\"/\\|?*";
- for (int pos = 0; pos < appId.length(); ++pos) {
- if (pos == aliasPos)
- continue;
- ushort ch = appId.at(pos).unicode();
- if ((ch < 0x20) || (ch > 0x7f) || strchr(forbiddenChars, ch & 0xff)) {
- throw Exception(Error::Parse, "must consist of printable ASCII characters only, except any of \'%1'")
- .arg(QString::fromLatin1(forbiddenChars));
- }
- if (spaceOnly)
- spaceOnly = QChar(ch).isSpace();
- }
- if (spaceOnly)
- throw Exception(Error::Parse, "must not consist of only white-space characters");
-
- return true;
- } catch (const Exception &e) {
- if (errorString)
- *errorString = e.errorString();
- return false;
- }
-}
-
-bool AbstractApplicationInfo::isValidIcon(const QString &icon, QString &errorString)
-{
- if (icon.isEmpty()) {
- errorString = qSL("it's empty");
- return false;
- }
-
- QFileInfo fileInfo(icon);
-
- if (fileInfo.fileName() != icon) {
- errorString = QString(qSL("'%1' is not a valid file name")).arg(icon);
- return false;
- }
-
- return true;
-}
//TODO Make this really unique
static int uniqueCounter = 0;
@@ -127,163 +62,113 @@ static int nextUniqueNumber() {
return uniqueCounter;
}
-AbstractApplicationInfo::AbstractApplicationInfo()
- : m_uniqueNumber(nextUniqueNumber())
+ApplicationInfo::ApplicationInfo(PackageInfo *packageInfo)
+ : m_packageInfo(packageInfo)
+ , m_uniqueNumber(nextUniqueNumber())
+{ }
+
+PackageInfo *ApplicationInfo::packageInfo() const
{
+ return m_packageInfo;
}
-QString AbstractApplicationInfo::id() const
+QString ApplicationInfo::id() const
{
return m_id;
}
-int AbstractApplicationInfo::uniqueNumber() const
+int ApplicationInfo::uniqueNumber() const
{
return m_uniqueNumber;
}
-QMap<QString, QString> AbstractApplicationInfo::names() const
-{
- return m_name;
-}
-
-QString AbstractApplicationInfo::name(const QString &language) const
-{
- return m_name.value(language);
-}
-
-QString AbstractApplicationInfo::icon() const
-{
- return m_icon;
-}
-
-QString AbstractApplicationInfo::documentUrl() const
-{
- return m_documentUrl;
-}
-
-QVariantMap AbstractApplicationInfo::applicationProperties() const
+QVariantMap ApplicationInfo::applicationProperties() const
{
return m_sysAppProperties;
}
-QVariantMap AbstractApplicationInfo::allAppProperties() const
+QVariantMap ApplicationInfo::allAppProperties() const
{
return m_allAppProperties;
}
-void AbstractApplicationInfo::validate() const Q_DECL_NOEXCEPT_EXPR(false)
-{
- QString errorMsg;
- if (!isValidApplicationId(id(), isAlias(), &errorMsg))
- throw Exception(Error::Parse, "the identifier (%1) is not a valid application-id: %2").arg(id()).arg(errorMsg);
-
- if (!isValidIcon(icon(), errorMsg))
- throw Exception(Error::Parse, "Invalid 'icon' field: %1").arg(errorMsg);
-
- if (names().isEmpty())
- throw Exception(Error::Parse, "the 'name' field must not be empty");
-
- // This check won't work during installations, since the icon file is extracted after info.json
- // if (!QFile::exists(displayIcon()))
- // throw Exception("the 'icon' field refers to a non-existent file");
-
- //TODO: check for valid capabilities
-}
-
-void AbstractApplicationInfo::read(QDataStream &ds)
-{
- ds >> m_id
- >> m_uniqueNumber
- >> m_name
- >> m_icon
- >> m_documentUrl
- >> m_sysAppProperties
- >> m_allAppProperties;
-
- uniqueCounter = qMax(uniqueCounter, m_uniqueNumber);
-}
-
-void AbstractApplicationInfo::writeToDataStream(QDataStream &ds) const
+void ApplicationInfo::writeToDataStream(QDataStream &ds) const
{
- ds << isAlias()
- << m_id
+ ds << m_id
<< m_uniqueNumber
- << m_name
- << m_icon
- << m_documentUrl
<< m_sysAppProperties
- << m_allAppProperties;
+ << m_allAppProperties
+ << m_codeFilePath
+ << m_runtimeName
+ << m_runtimeParameters
+ << m_supportsApplicationInterface
+ << m_capabilities
+ << m_openGLConfiguration;
}
-AbstractApplicationInfo *AbstractApplicationInfo::readFromDataStream(QDataStream &ds)
+ApplicationInfo *ApplicationInfo::readFromDataStream(PackageInfo *pkg, QDataStream &ds)
{
- bool isAlias;
- ds >> isAlias;
+ QScopedPointer<ApplicationInfo> app(new ApplicationInfo(pkg));
- QScopedPointer<AbstractApplicationInfo> app;
+ ds >> app->m_id
+ >> app->m_uniqueNumber
+ >> app->m_sysAppProperties
+ >> app->m_allAppProperties
+ >> app->m_codeFilePath
+ >> app->m_runtimeName
+ >> app->m_runtimeParameters
+ >> app->m_supportsApplicationInterface
+ >> app->m_capabilities
+ >> app->m_openGLConfiguration;
- if (isAlias)
- app.reset(new ApplicationAliasInfo);
- else
- app.reset(new ApplicationInfo);
-
- app->read(ds);
+ uniqueCounter = qMax(uniqueCounter, app->m_uniqueNumber);
+ app->m_capabilities.sort();
return app.take();
}
-void AbstractApplicationInfo::toVariantMapHelper(QVariantMap &map) const
+
+QVariantMap ApplicationInfo::toVariantMap() const
{
+ QVariantMap map;
//TODO: check if we can find a better method to keep this as similar as possible to
// ApplicationManager::get().
- // This is used for RuntimeInterface::startApplication(), ContainerInterface and
- // ApplicationInstaller::taskRequestingInstallationAcknowledge.
+ // This is used for RuntimeInterface::startApplication() and the ContainerInterface
map[qSL("id")] = m_id;
map[qSL("uniqueNumber")] = m_uniqueNumber;
{
QVariantMap displayName;
- auto names = m_name;
+ auto names = packageInfo()->names();
for (auto it = names.constBegin(); it != names.constEnd(); ++it)
displayName.insert(it.key(), it.value());
map[qSL("displayName")] = displayName;
}
- map[qSL("displayIcon")] = m_icon;
+ map[qSL("displayIcon")] = packageInfo()->icon();
map[qSL("applicationProperties")] = m_allAppProperties;
-}
+ map[qSL("codeFilePath")] = m_codeFilePath;
+ map[qSL("runtimeName")] = m_runtimeName;
+ map[qSL("runtimeParameters")] = m_runtimeParameters;
+ map[qSL("capabilities")] = m_capabilities;
+ map[qSL("mimeTypes")] = m_supportedMimeTypes;
+
+ map[qSL("categories")] = packageInfo()->categories();
+ map[qSL("version")] = packageInfo()->version();
+ map[qSL("baseDir")] = packageInfo()->baseDir().absolutePath();
+ map[qSL("codeDir")] = map[qSL("baseDir")]; // 5.12 backward compatibility
+ map[qSL("manifestDir")] = map[qSL("baseDir")]; // 5.12 backward compatibility
+ map[qSL("installationLocationId")] = packageInfo()->installationReport() ? qSL("internal-0") : QString();
+ map[qSL("supportsApplicationInterface")] = m_supportsApplicationInterface;
+ map[qSL("dlt")] = packageInfo()->dltConfiguration();
-QVariantMap AbstractApplicationInfo::toVariantMap() const
-{
- QVariantMap map;
- toVariantMapHelper(map);
return map;
}
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// ApplicationInfo
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-ApplicationInfo::ApplicationInfo()
-{ }
-
-void ApplicationInfo::validate() const Q_DECL_NOEXCEPT_EXPR(false)
-{
- AbstractApplicationInfo::validate();
-
- if (absoluteCodeFilePath().isEmpty())
- throw Exception(Error::Parse, "the 'code' field must not be empty");
-
- if (runtimeName().isEmpty())
- throw Exception(Error::Parse, "the 'runtimeName' field must not be empty");
-}
-
QString ApplicationInfo::absoluteCodeFilePath() const
{
- QString code = m_codeFilePath;
- return code.isEmpty() ? QString() : QDir(codeDir()).absoluteFilePath(code);
+ return toAbsoluteFilePath(m_codeFilePath, packageInfo()->baseDir().path());
}
QString ApplicationInfo::codeFilePath() const
@@ -301,11 +186,6 @@ QVariantMap ApplicationInfo::runtimeParameters() const
return m_runtimeParameters;
}
-bool ApplicationInfo::isBuiltIn() const
-{
- return m_builtIn;
-}
-
QStringList ApplicationInfo::capabilities() const
{
return m_capabilities;
@@ -313,17 +193,7 @@ QStringList ApplicationInfo::capabilities() const
QStringList ApplicationInfo::supportedMimeTypes() const
{
- return m_mimeTypes;
-}
-
-QStringList ApplicationInfo::categories() const
-{
- return m_categories;
-}
-
-QString ApplicationInfo::version() const
-{
- return m_version;
+ return m_supportedMimeTypes;
}
QVariantMap ApplicationInfo::openGLConfiguration() const
@@ -331,114 +201,9 @@ QVariantMap ApplicationInfo::openGLConfiguration() const
return m_openGLConfiguration;
}
-QVariantList ApplicationInfo::intents() const
-{
- return m_intents;
-}
-
-void ApplicationInfo::setBuiltIn(bool builtIn)
-{
- m_builtIn = builtIn;
-}
-
-void ApplicationInfo::setSupportsApplicationInterface(bool supportsAppInterface)
-{
- m_supportsApplicationInterface = supportsAppInterface;
-}
-
-void ApplicationInfo::writeToDataStream(QDataStream &ds) const
-{
- AbstractApplicationInfo::writeToDataStream(ds);
-
- QByteArray serializedReport;
-
- if (auto report = installationReport()) {
- QBuffer buffer(&serializedReport);
- buffer.open(QBuffer::WriteOnly);
- report->serialize(&buffer);
- }
-
- ds << m_codeFilePath
- << m_runtimeName
- << m_runtimeParameters
- << m_supportsApplicationInterface
- << m_builtIn
- << m_capabilities
- << m_categories
- << m_mimeTypes
- << m_version
- << m_openGLConfiguration
- << serializedReport
- << m_manifestDir.absolutePath()
- << m_codeDir.absolutePath()
- << m_uid
- << m_dlt
- << m_intents;
-}
-
bool ApplicationInfo::supportsApplicationInterface() const
{
return m_supportsApplicationInterface;
}
-void ApplicationInfo::read(QDataStream &ds)
-{
- AbstractApplicationInfo::read(ds);
-
- QString codeDir;
- QString manifestDir;
- QByteArray installationReport;
-
- ds >> m_codeFilePath
- >> m_runtimeName
- >> m_runtimeParameters
- >> m_supportsApplicationInterface
- >> m_builtIn
- >> m_capabilities
- >> m_categories
- >> m_mimeTypes
- >> m_version
- >> m_openGLConfiguration
- >> installationReport
- >> manifestDir
- >> codeDir
- >> m_uid
- >> m_dlt
- >> m_intents;
-
- m_capabilities.sort();
- m_categories.sort();
- m_mimeTypes.sort();
-
- m_codeDir.setPath(codeDir);
- m_manifestDir.setPath(manifestDir);
- if (!installationReport.isEmpty()) {
- QBuffer buffer(&installationReport);
- buffer.open(QBuffer::ReadOnly);
- m_installationReport.reset(new InstallationReport(m_id));
- if (!m_installationReport->deserialize(&buffer))
- m_installationReport.reset();
- }
-}
-
-void ApplicationInfo::toVariantMapHelper(QVariantMap &map) const
-{
- AbstractApplicationInfo::toVariantMapHelper(map);
-
- map[qSL("codeFilePath")] = m_codeFilePath;
- map[qSL("runtimeName")] = m_runtimeName;
- map[qSL("runtimeParameters")] = m_runtimeParameters;
- map[qSL("capabilities")] = m_capabilities;
- map[qSL("mimeTypes")] = m_mimeTypes;
- map[qSL("categories")] = m_categories;
- map[qSL("version")] = m_version;
- map[qSL("codeDir")] = m_codeDir.absolutePath();
- map[qSL("manifestDir")] = m_manifestDir.absolutePath();
- map[qSL("installationLocationId")] = installationReport() ? installationReport()->installationLocationId()
- : QString();
- map[qSL("supportsApplicationInterface")] = m_supportsApplicationInterface;
- map[qSL("dlt")] = m_dlt;
- map[qSL("intents")] = m_intents;
-}
-
QT_END_NAMESPACE_AM
diff --git a/src/application-lib/applicationinfo.h b/src/application-lib/applicationinfo.h
index aefce00c..6dd9afa5 100644
--- a/src/application-lib/applicationinfo.h
+++ b/src/application-lib/applicationinfo.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -42,137 +42,70 @@
#pragma once
-#include <QDataStream>
#include <QDir>
#include <QMap>
#include <QString>
#include <QStringList>
#include <QVariantMap>
+#include <QVector>
#include <QtAppManCommon/global.h>
-#include <QtAppManApplication/installationreport.h>
+
+QT_FORWARD_DECLARE_CLASS(QDataStream)
QT_BEGIN_NAMESPACE_AM
-class ApplicationManager;
-class InstallationReport;
+class PackageInfo;
-class AbstractApplicationInfo
+class ApplicationInfo
{
public:
- AbstractApplicationInfo();
- virtual ~AbstractApplicationInfo() {}
+ ApplicationInfo(PackageInfo *packageInfo);
+
+ PackageInfo *packageInfo() const;
+ QVariantMap toVariantMap() const;
QString id() const;
int uniqueNumber() const;
- QMap<QString, QString> names() const;
- QString name(const QString &language) const;
- QString icon() const;
- QString documentUrl() const;
QVariantMap applicationProperties() const;
QVariantMap allAppProperties() const;
-
- QVariantMap toVariantMap() const;
- virtual void toVariantMapHelper(QVariantMap &map) const;
-
- virtual bool isAlias() const = 0;
- virtual void writeToDataStream(QDataStream &ds) const;
- virtual void validate() const Q_DECL_NOEXCEPT_EXPR(false);
-
- static bool isValidApplicationId(const QString &appId, bool isAliasName = false, QString *errorString = nullptr);
- static bool isValidIcon(const QString &icon, QString &errorString);
- static AbstractApplicationInfo *readFromDataStream(QDataStream &ds);
-
-protected:
- virtual void read(QDataStream &ds);
-
- // static part from info.json
- QString m_id;
- int m_uniqueNumber;
-
- QMap<QString, QString> m_name; // language -> name
- QString m_icon; // relative to info.json location
- QString m_documentUrl;
- QVariantMap m_sysAppProperties;
- QVariantMap m_allAppProperties;
-
- friend class YamlApplicationScanner;
-};
-
-class ApplicationAliasInfo : public AbstractApplicationInfo
-{
-public:
- bool isAlias() const override { return true; }
-};
-
-class ApplicationInfo : public AbstractApplicationInfo
-{
-public:
- ApplicationInfo();
-
- bool isAlias() const override { return false; }
- void writeToDataStream(QDataStream &ds) const override;
- void validate() const Q_DECL_NOEXCEPT_EXPR(false) override;
-
- const QDir &codeDir() const { return m_codeDir; }
QString absoluteCodeFilePath() const;
QString codeFilePath() const;
QString runtimeName() const;
QVariantMap runtimeParameters() const;
- QVariantMap environmentVariables() const { return m_environmentVariables; }
- bool isBuiltIn() const;
QStringList capabilities() const;
QStringList supportedMimeTypes() const;
- QStringList categories() const;
- QString version() const;
QVariantMap openGLConfiguration() const;
- QVariantList intents() const;
bool supportsApplicationInterface() const;
- void setSupportsApplicationInterface(bool supportsAppInterface);
- void setBuiltIn(bool builtIn);
+ void writeToDataStream(QDataStream &ds) const;
+ static ApplicationInfo *readFromDataStream(PackageInfo *pkg, QDataStream &ds);
- const InstallationReport *installationReport() const { return m_installationReport.data(); }
- void setInstallationReport(InstallationReport *report) { m_installationReport.reset(report); }
- QString manifestDir() const { return m_manifestDir.absolutePath(); }
- uint uid() const { return m_uid; }
- void setManifestDir(const QString &path) { m_manifestDir.setPath(path); }
- void setCodeDir(const QString &path) { m_codeDir.setPath(path); }
+private:
+ void read(QDataStream &ds);
- void toVariantMapHelper(QVariantMap &map) const override;
+ // static part from info.json
+ PackageInfo *m_packageInfo;
-private:
- void read(QDataStream &ds) override;
+ QString m_id;
+ int m_uniqueNumber;
+
+ QVariantMap m_sysAppProperties;
+ QVariantMap m_allAppProperties;
QString m_codeFilePath; // relative to info.json location
QString m_runtimeName;
QVariantMap m_runtimeParameters;
- QVariantMap m_environmentVariables;
bool m_supportsApplicationInterface = false;
-
- bool m_builtIn = false; // system app - not removable
-
QStringList m_capabilities;
- QStringList m_categories;
- QStringList m_mimeTypes;
-
- QString m_version;
-
QVariantMap m_openGLConfiguration;
- QVariantList m_intents;
- QVariantMap m_dlt;
-
- // added by installer
- QScopedPointer<InstallationReport> m_installationReport;
- QDir m_manifestDir;
- QDir m_codeDir;
- uint m_uid = uint(-1); // unix user id - move to installationReport
+ QStringList m_supportedMimeTypes; // deprecated
- friend class YamlApplicationScanner;
friend class ApplicationManager; // needed to update installation status
- friend class ApplicationDatabase; // needed to create ApplicationInfo objects
+ friend class PackageDatabase; // needed to create ApplicationInfo objects
friend class InstallationTask; // needed to set m_uid and m_builtin during the installation
+ friend class YamlPackageScanner;
Q_DISABLE_COPY(ApplicationInfo)
};
diff --git a/src/application-lib/applicationinterface.cpp b/src/application-lib/applicationinterface.cpp
index ca13eaf3..1ba0ea75 100644
--- a/src/application-lib/applicationinterface.cpp
+++ b/src/application-lib/applicationinterface.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/application-lib/applicationinterface.h b/src/application-lib/applicationinterface.h
index 5150546e..61e05118 100644
--- a/src/application-lib/applicationinterface.h
+++ b/src/application-lib/applicationinterface.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/application-lib/installationreport.cpp b/src/application-lib/installationreport.cpp
index 0b4e5c67..cf236dd7 100644
--- a/src/application-lib/installationreport.cpp
+++ b/src/application-lib/installationreport.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -50,7 +51,7 @@
#include "global.h"
#include "qtyaml.h"
-#include "applicationinfo.h"
+#include "packageinfo.h"
#include "utilities.h"
#include "exception.h"
#include "installationreport.h"
@@ -69,28 +70,18 @@ static const unsigned char privateHmacKeyData[64] = {
};
-InstallationReport::InstallationReport(const QString &applicationId)
- : m_applicationId(applicationId)
+InstallationReport::InstallationReport(const QString &packageId)
+ : m_packageId(packageId)
{ }
-QString InstallationReport::applicationId() const
+QString InstallationReport::packageId() const
{
- return m_applicationId;
+ return m_packageId;
}
-void InstallationReport::setApplicationId(const QString &applicationId)
+void InstallationReport::setPackageId(const QString &packageId)
{
- m_applicationId = applicationId;
-}
-
-QString InstallationReport::installationLocationId() const
-{
- return m_installationLocationId;
-}
-
-void InstallationReport::setInstallationLocationId(const QString &installationLocationId)
-{
- m_installationLocationId = installationLocationId;
+ m_packageId = packageId;
}
QVariantMap InstallationReport::extraMetaData() const
@@ -170,91 +161,83 @@ void InstallationReport::addFiles(const QStringList &files)
bool InstallationReport::isValid() const
{
- return AbstractApplicationInfo::isValidApplicationId(m_applicationId) && !m_digest.isEmpty() && !m_files.isEmpty();
+ return PackageInfo::isValidApplicationId(m_packageId) && !m_digest.isEmpty() && !m_files.isEmpty();
}
-bool InstallationReport::deserialize(QIODevice *from)
+void InstallationReport::deserialize(QIODevice *from)
{
if (!from || !from->isReadable() || (from->size() > 2*1024*1024))
- return false;
+ throw Exception("Installation report is invalid");
m_digest.clear();
m_files.clear();
- QtYaml::ParseError error;
- QVector<QVariant> docs = QtYaml::variantDocumentsFromYaml(from->readAll(), &error);
-
- if (error.error != QJsonParseError::NoError)
- return false;
-
- try {
- checkYamlFormat(docs, 3 /*number of expected docs*/, { "am-installation-report" }, 1);
- } catch (const Exception &) {
- return false;
- }
+ auto docs = YamlParser::parseAllDocuments(from->readAll());
+ checkYamlFormat(docs, 3 /*number of expected docs*/, { { qSL("am-installation-report"), 3 } });
const QVariantMap &root = docs.at(1).toMap();
try {
- if (m_applicationId.isEmpty()) {
- m_applicationId = root[qSL("applicationId")].toString();
- if (m_applicationId.isEmpty())
- throw false;
- } else if (root[qSL("applicationId")].toString() != m_applicationId) {
- throw false;
+ if (m_packageId.isEmpty()) {
+ m_packageId = root[qSL("packageId")].toString();
+ if (m_packageId.isEmpty())
+ throw Exception("packageId is empty");
+ } else if (root[qSL("packageId")].toString() != m_packageId) {
+ throw Exception("packageId does not match: expected '%1', but got '%2'")
+ .arg(m_packageId).arg(root[qSL("packageId")].toString());
}
- m_installationLocationId = root[qSL("installationLocationId")].toString();
m_diskSpaceUsed = root[qSL("diskSpaceUsed")].toULongLong();
m_digest = QByteArray::fromHex(root[qSL("digest")].toString().toLatin1());
if (m_digest.isEmpty())
- throw false;
+ throw Exception("digest is empty");
auto devSig = root.find(qSL("developerSignature"));
if (devSig != root.end()) {
m_developerSignature = QByteArray::fromBase64(devSig.value().toString().toLatin1());
if (m_developerSignature.isEmpty())
- throw false;
+ throw Exception("developerSignature is empty");
}
auto storeSig = root.find(qSL("storeSignature"));
if (storeSig != root.end()) {
m_storeSignature = QByteArray::fromBase64(storeSig.value().toString().toLatin1());
if (m_storeSignature.isEmpty())
- throw false;
+ throw Exception("storeSignature is empty");
}
auto extra = root.find(qSL("extra"));
if (extra != root.end()) {
m_extraMetaData = extra.value().toMap();
if (m_extraMetaData.isEmpty())
- throw false;
+ throw Exception("extra metadata is empty");
}
auto extraSigned = root.find(qSL("extraSigned"));
if (extraSigned != root.end()) {
m_extraSignedMetaData = extraSigned.value().toMap();
if (m_extraSignedMetaData.isEmpty())
- throw false;
+ throw Exception("extraSigned metadata is empty");
}
m_files = root[qSL("files")].toStringList();
if (m_files.isEmpty())
- throw false;
+ throw Exception("No files");
// see if the file has been tampered with by checking the hmac
QByteArray hmacFile = QByteArray::fromHex(docs[2].toMap().value(qSL("hmac")).toString().toLatin1());
- QByteArray hmacKey = QByteArray::fromRawData((const char *) privateHmacKeyData, sizeof(privateHmacKeyData));
- QByteArray hmacCalc= QMessageAuthenticationCode::hash(QtYaml::yamlFromVariantDocuments({ docs[0], docs[1] }, QtYaml::BlockStyle),
- hmacKey,
- QCryptographicHash::Sha256);
+ QByteArray hmacKey = QByteArray::fromRawData(reinterpret_cast<const char *>(privateHmacKeyData),
+ sizeof(privateHmacKeyData));
- if (hmacFile != hmacCalc)
- throw false;
+ QByteArray out = QtYaml::yamlFromVariantDocuments({ docs[0], docs[1] }, QtYaml::BlockStyle);
+ QByteArray hmacCalc= QMessageAuthenticationCode::hash(out, hmacKey, QCryptographicHash::Sha256);
- return true;
- } catch (bool) {
+ if (hmacFile != hmacCalc) {
+ throw Exception("HMAC does not match: expected '%1', but got '%2'")
+ .arg(hmacCalc.toHex()).arg(hmacFile.toHex());
+ }
+ } catch (const Exception &) {
m_digest.clear();
m_diskSpaceUsed = 0;
m_files.clear();
- return false;
+ throw;
}
}
@@ -264,12 +247,11 @@ bool InstallationReport::serialize(QIODevice *to) const
return false;
QVariantMap header {
- { "formatVersion", 1 },
+ { "formatVersion", 3 },
{ "formatType", "am-installation-report" }
};
QVariantMap root {
- { qSL("applicationId"), applicationId() },
- { qSL("installationLocationId"), installationLocationId() },
+ { qSL("packageId"), packageId() },
{ qSL("diskSpaceUsed"), diskSpaceUsed() },
{ qSL("digest"), QLatin1String(digest().toHex()) }
};
@@ -289,15 +271,15 @@ bool InstallationReport::serialize(QIODevice *to) const
docs << root;
// generate hmac to prevent tampering
- QByteArray hmacKey = QByteArray::fromRawData((const char *) privateHmacKeyData, sizeof(privateHmacKeyData));
- QByteArray hmacCalc= QMessageAuthenticationCode::hash(QtYaml::yamlFromVariantDocuments({ docs[0], docs[1] }, QtYaml::BlockStyle),
- hmacKey,
- QCryptographicHash::Sha256);
-
- QVariantMap footer { { qSL("hmac"), QString::fromLatin1(hmacCalc.toHex()) } };
- docs << footer;
-
- QByteArray out = QtYaml::yamlFromVariantDocuments(docs, QtYaml::BlockStyle);
+ QByteArray hmacKey = QByteArray::fromRawData(reinterpret_cast<const char *>(privateHmacKeyData),
+ sizeof(privateHmacKeyData));
+ QByteArray out = QtYaml::yamlFromVariantDocuments({ docs[0], docs[1] }, QtYaml::BlockStyle);
+ QByteArray hmacCalc= QMessageAuthenticationCode::hash(out, hmacKey, QCryptographicHash::Sha256);
+
+ // add another YAML document with a single key/value (way faster than using QtYaml)
+ out += "---\nhmac: '";
+ out += hmacCalc.toHex();
+ out += "'\n";
return (to->write(out) == out.size());
}
diff --git a/src/application-lib/installationreport.h b/src/application-lib/installationreport.h
index a619c80a..aa01f658 100644
--- a/src/application-lib/installationreport.h
+++ b/src/application-lib/installationreport.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -55,13 +56,10 @@ QT_BEGIN_NAMESPACE_AM
class InstallationReport
{
public:
- InstallationReport(const QString &applicationId = QString());
+ InstallationReport(const QString &packageId = QString());
- QString applicationId() const;
- void setApplicationId(const QString &applicationId);
-
- QString installationLocationId() const;
- void setInstallationLocationId(const QString &installationLocationId);
+ QString packageId() const;
+ void setPackageId(const QString &packageId);
QVariantMap extraMetaData() const;
void setExtraMetaData(const QVariantMap &extraMetaData);
@@ -86,12 +84,11 @@ public:
bool isValid() const;
- bool deserialize(QIODevice *from);
+ void deserialize(QIODevice *from);
bool serialize(QIODevice *to) const;
private:
- QString m_applicationId;
- QString m_installationLocationId;
+ QString m_packageId;
QByteArray m_digest;
quint64 m_diskSpaceUsed = 0;
QStringList m_files;
diff --git a/src/application-lib/intentinfo.cpp b/src/application-lib/intentinfo.cpp
new file mode 100644
index 00000000..43892939
--- /dev/null
+++ b/src/application-lib/intentinfo.cpp
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QDataStream>
+
+#include "intentinfo.h"
+#include "packageinfo.h"
+
+QT_BEGIN_NAMESPACE_AM
+
+
+IntentInfo::IntentInfo(PackageInfo *packageInfo)
+ : m_packageInfo(packageInfo)
+{ }
+
+IntentInfo::~IntentInfo()
+{ }
+
+QString IntentInfo::id() const
+{
+ return m_id;
+}
+
+IntentInfo::Visibility IntentInfo::visibility() const
+{
+ return m_visibility;
+}
+
+QStringList IntentInfo::requiredCapabilities() const
+{
+ return m_requiredCapabilities;
+}
+
+QVariantMap IntentInfo::parameterMatch() const
+{
+ return m_parameterMatch;
+}
+
+QString IntentInfo::handlingApplicationId() const
+{
+ return m_handlingApplicationId;
+}
+
+QStringList IntentInfo::categories() const
+{
+ return m_categories.isEmpty() ? m_packageInfo->categories() : m_categories;
+}
+
+QMap<QString, QString> IntentInfo::names() const
+{
+ return m_names.isEmpty() ? m_packageInfo->names() : m_names;
+}
+
+QString IntentInfo::name(const QString &language) const
+{
+ return m_names.isEmpty() ? m_packageInfo->name(language) : m_names.value(language);
+}
+
+QMap<QString, QString> IntentInfo::descriptions() const
+{
+ return m_descriptions;
+}
+
+QString IntentInfo::description(const QString &language) const
+{
+ return m_descriptions.value(language);
+}
+
+QString IntentInfo::icon() const
+{
+ return m_icon.isEmpty() ? m_packageInfo->icon() : m_icon;
+}
+
+void IntentInfo::writeToDataStream(QDataStream &ds) const
+{
+ ds << m_id
+ << (m_visibility == Public ? qSL("public") : qSL("private"))
+ << m_requiredCapabilities
+ << m_parameterMatch
+ << m_handlingApplicationId
+ << m_categories
+ << m_names
+ << m_descriptions
+ << m_icon;
+}
+
+IntentInfo *IntentInfo::readFromDataStream(PackageInfo *pkg, QDataStream &ds)
+{
+ QScopedPointer<IntentInfo> intent(new IntentInfo(pkg));
+ QString visibilityStr;
+
+ ds >> intent->m_id
+ >> visibilityStr
+ >> intent->m_requiredCapabilities
+ >> intent->m_parameterMatch
+ >> intent->m_handlingApplicationId
+ >> intent->m_categories
+ >> intent->m_names
+ >> intent->m_descriptions
+ >> intent->m_icon;
+
+ intent->m_visibility = (visibilityStr == qSL("public")) ? Public : Private;
+ intent->m_categories.sort();
+
+ return intent.take();
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/application-lib/intentinfo.h b/src/application-lib/intentinfo.h
new file mode 100644
index 00000000..9834e42c
--- /dev/null
+++ b/src/application-lib/intentinfo.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QMap>
+#include <QString>
+#include <QStringList>
+#include <QVariantMap>
+#include <QVector>
+
+#include <QtAppManCommon/global.h>
+
+QT_FORWARD_DECLARE_CLASS(QDataStream)
+
+QT_BEGIN_NAMESPACE_AM
+
+class YamlPackageScanner;
+class PackageInfo;
+
+class IntentInfo
+{
+public:
+ IntentInfo(PackageInfo *packageInfo);
+ ~IntentInfo();
+
+ enum Visibility {
+ Public,
+ Private
+ };
+
+ QString id() const;
+ Visibility visibility() const;
+ QStringList requiredCapabilities() const;
+ QVariantMap parameterMatch() const;
+ QString handlingApplicationId() const;
+
+ QStringList categories() const;
+
+ QMap<QString, QString> names() const;
+ QString name(const QString &language) const;
+ QMap<QString, QString> descriptions() const;
+ QString description(const QString &language) const;
+ QString icon() const;
+
+ void writeToDataStream(QDataStream &ds) const;
+ static IntentInfo *readFromDataStream(PackageInfo *pkg, QDataStream &ds);
+
+private:
+ PackageInfo *m_packageInfo;
+ QString m_id;
+ Visibility m_visibility = Public;
+ QStringList m_requiredCapabilities;
+ QVariantMap m_parameterMatch;
+
+ QString m_handlingApplicationId;
+ QStringList m_categories;
+ QMap<QString, QString> m_names; // language -> name
+ QMap<QString, QString> m_descriptions; // language -> description
+ QString m_icon; // relative to info.json location
+
+ friend class YamlPackageScanner;
+ Q_DISABLE_COPY(IntentInfo)
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/application-lib/packagedatabase.cpp b/src/application-lib/packagedatabase.cpp
new file mode 100644
index 00000000..de12f572
--- /dev/null
+++ b/src/application-lib/packagedatabase.cpp
@@ -0,0 +1,257 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QDir>
+#include <QFile>
+#include <QScopedPointer>
+#include <QDataStream>
+
+#include "packagedatabase.h"
+#include "packageinfo.h"
+#include "yamlpackagescanner.h"
+#include "applicationinfo.h"
+#include "installationreport.h"
+#include "exception.h"
+#include "logging.h"
+#include "configcache.h"
+
+QT_BEGIN_NAMESPACE_AM
+
+// the templated adaptor class needed to instantiate ConfigCache<PackageInfo> in parse() below
+template<> class ConfigCacheAdaptor<PackageInfo>
+{
+public:
+ PackageInfo *loadFromSource(QIODevice *source, const QString &fileName)
+ {
+ return YamlPackageScanner().scan(source, fileName);
+ }
+ PackageInfo *loadFromCache(QDataStream &ds)
+ {
+ return PackageInfo::readFromDataStream(ds);
+ }
+ void saveToCache(QDataStream &ds, const PackageInfo *pi)
+ {
+ pi->writeToDataStream(ds);
+ }
+
+ void preProcessSourceContent(QByteArray &, const QString &) { }
+ void merge(PackageInfo *, const PackageInfo *) { }
+
+ QStringList *warnings;
+};
+
+
+PackageDatabase::PackageDatabase(const QStringList &builtInPackagesDirs,
+ const QString &installedPackagesDir)
+ : m_builtInPackagesDirs(builtInPackagesDirs)
+ , m_installedPackagesDir(installedPackagesDir)
+{ }
+
+PackageDatabase::PackageDatabase(const QString &singlePackagePath)
+ : m_singlePackagePath(singlePackagePath)
+{
+ Q_ASSERT(!singlePackagePath.isEmpty());
+}
+
+PackageDatabase::~PackageDatabase()
+{
+ qDeleteAll(m_builtInPackages);
+ qDeleteAll(m_installedPackages);
+}
+
+QString PackageDatabase::installedPackagesDir() const
+{
+ return m_installedPackagesDir;
+}
+
+void PackageDatabase::enableLoadFromCache()
+{
+ if (m_parsed)
+ qCWarning(LogSystem) << "PackageDatabase cannot change the caching mode after the initial load";
+ m_loadFromCache = true;
+}
+
+void PackageDatabase::enableSaveToCache()
+{
+ if (m_parsed)
+ qCWarning(LogSystem) << "PackageDatabase cannot change the caching mode after the initial load";
+ m_saveToCache = true;
+}
+
+bool PackageDatabase::builtInHasRemovableUpdate(PackageInfo *packageInfo) const
+{
+ if (!packageInfo || packageInfo->isBuiltIn() || !m_installedPackages.contains(packageInfo))
+ return false;
+ for (const auto *pi : m_builtInPackages) {
+ if (pi->id() == packageInfo->id())
+ return true;
+ }
+ return false;
+}
+
+QStringList PackageDatabase::findManifestsInDir(const QDir &manifestDir, bool scanningBuiltInApps)
+{
+ QStringList files;
+
+ auto flags = scanningBuiltInApps ? QDir::Dirs | QDir::NoDotAndDotDot
+ : QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks;
+ const QDir baseDir(manifestDir);
+ const QStringList pkgDirNames = baseDir.entryList(flags);
+
+ for (const QString &pkgDirName : pkgDirNames) {
+ try {
+ // ignore left-overs from the installer
+ if (pkgDirName.endsWith('+') || pkgDirName.endsWith('-'))
+ continue;
+
+ // ignore filesystem problems
+ QDir pkgDir = baseDir.absoluteFilePath(pkgDirName);
+ if (!pkgDir.exists())
+ continue;
+
+ // ignore directory names with weird/forbidden characters
+ QString pkgIdError;
+ if (!PackageInfo::isValidApplicationId(pkgDirName, &pkgIdError))
+ throw Exception("not a valid package-id: %1").arg(pkgIdError);
+
+ if (!pkgDir.exists(qSL("info.yaml")))
+ throw Exception("couldn't find an info.yaml manifest");
+ if (!scanningBuiltInApps && !pkgDir.exists(qSL(".installation-report.yaml")))
+ throw Exception("found a non-built-in package without an installation report");
+
+ QString manifestPath = pkgDir.absoluteFilePath(qSL("info.yaml"));
+ files << manifestPath;
+
+ } catch (const Exception &e) {
+ qCDebug(LogSystem) << "Ignoring package" << pkgDirName << ":" << e.what();
+ }
+ }
+ return files;
+}
+
+void PackageDatabase::parse()
+{
+ if (m_parsed)
+ throw Exception("PackageDatabase::parse() has been called multiple times");
+ m_parsed = true;
+
+ if (!m_singlePackagePath.isEmpty()) {
+ try {
+ m_builtInPackages.append(PackageInfo::fromManifest(m_singlePackagePath));
+ } catch (const Exception &e) {
+ throw Exception("Failed to load manifest for package: %1").arg(e.errorString());
+ }
+ } else {
+ QStringList manifestFiles;
+
+ // parallelize this
+ for (const QString &dir : m_builtInPackagesDirs)
+ manifestFiles << findManifestsInDir(dir, true);
+ int installedOffset = manifestFiles.size();
+ if (!m_installedPackagesDir.isEmpty())
+ manifestFiles << findManifestsInDir(m_installedPackagesDir, false);
+
+ AbstractConfigCache::Options cacheOptions = AbstractConfigCache::None;
+ if (!m_loadFromCache)
+ cacheOptions |= AbstractConfigCache::ClearCache;
+ if (!m_loadFromCache && !m_saveToCache)
+ cacheOptions |= AbstractConfigCache::NoCache;
+
+ ConfigCache<PackageInfo> cache(manifestFiles, qSL("appdb"), cacheOptions);
+ cache.parse();
+
+ for (int i = 0; i < manifestFiles.size(); ++i) {
+ bool isBuiltIn = (i < installedOffset);
+ QString manifestFile = manifestFiles.at(i);
+ QDir pkgDir = QFileInfo(manifestFile).dir();
+ QScopedPointer<PackageInfo>pkg(cache.takeResult(i));
+
+ if (pkg->id() != pkgDir.dirName()) {
+ throw Exception("an info.yaml for built-in packages must be in a directory that has"
+ " the same name as the package's id: found '%1'").arg(pkg->id());
+ }
+ if (isBuiltIn) {
+ pkg->setBuiltIn(true);
+ m_builtInPackages.append(pkg.take());
+ } else { // 3rd-party apps
+ QFile f(pkgDir.absoluteFilePath(qSL(".installation-report.yaml")));
+ if (!f.open(QFile::ReadOnly))
+ throw Exception(f, "failed to open the installation report");
+
+ QScopedPointer<InstallationReport> report(new InstallationReport(pkg->id()));
+ try {
+ report->deserialize(&f);
+ } catch (const Exception &e) {
+ throw Exception("Failed to deserialize the installation report %1: %2")
+ .arg(f.fileName()).arg(e.errorString());
+ }
+
+ pkg->setInstallationReport(report.take());
+ pkg->setBaseDir(pkgDir.path());
+ m_installedPackages.append(pkg.take());
+ }
+ }
+ }
+}
+
+void PackageDatabase::addPackageInfo(PackageInfo *package)
+{
+ m_installedPackages.append(package);
+}
+
+void PackageDatabase::removePackageInfo(PackageInfo *package)
+{
+ if (m_installedPackages.removeAll(package))
+ delete package;
+}
+
+QVector<PackageInfo *> PackageDatabase::installedPackages() const
+{
+ return m_installedPackages;
+}
+
+QVector<PackageInfo *> PackageDatabase::builtInPackages() const
+{
+ return m_builtInPackages;
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/installer-lib/installationlocation.h b/src/application-lib/packagedatabase.h
index 43e921ab..e1bbb52a 100644
--- a/src/installer-lib/installationlocation.h
+++ b/src/application-lib/packagedatabase.h
@@ -1,10 +1,10 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
-** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -43,42 +43,53 @@
#pragma once
#include <QtAppManCommon/global.h>
+#include <QVector>
#include <QString>
-#include <QVariantMap>
+
+#include <QtAppManApplication/packageinfo.h>
QT_BEGIN_NAMESPACE_AM
-class InstallationLocation
+class PackageInfo;
+
+
+class PackageDatabase
{
public:
- static const InstallationLocation invalid;
+ PackageDatabase(const QStringList &builtInPackagesDirs, const QString &installedPackagesDir = QString());
+ PackageDatabase(const QString &singlePackagePath);
+ ~PackageDatabase();
- bool operator==(const InstallationLocation &other) const;
- inline bool operator!=(const InstallationLocation &other) const { return !((*this) == other); }
+ QString installedPackagesDir() const;
- QString id() const;
- int index() const;
+ void enableLoadFromCache();
+ void enableSaveToCache();
- QString installationPath() const;
- QString documentPath() const;
+ void parse();
- bool installationDeviceFreeSpace(quint64 *bytesTotal, quint64 *bytesFree) const;
- bool documentDeviceFreeSpace(quint64 *bytesTotal, quint64 *bytesFree) const;
+ QVector<PackageInfo *> builtInPackages() const;
+ QVector<PackageInfo *> installedPackages() const;
- bool isValid() const;
- bool isDefault() const;
+ // runtime installations
+ void addPackageInfo(PackageInfo *package);
+ void removePackageInfo(PackageInfo *package);
- QVariantMap toVariantMap() const;
+private:
+ Q_DISABLE_COPY(PackageDatabase)
- static QVector<InstallationLocation> parseInstallationLocations(const QVariantList &list,
- const QString &hardwareId) Q_DECL_NOEXCEPT_EXPR(false);
+ bool builtInHasRemovableUpdate(PackageInfo *packageInfo) const;
+ QStringList findManifestsInDir(const QDir &manifestDir, bool scanningBuiltInApps);
+
+ bool m_loadFromCache = false;
+ bool m_saveToCache = false;
+ bool m_parsed = false;
+ QStringList m_builtInPackagesDirs;
+ QString m_installedPackagesDir;
+ QString m_singlePackagePath;
+
+ QVector<PackageInfo *> m_builtInPackages;
+ QVector<PackageInfo *> m_installedPackages;
-private:
- bool m_valid = false;
- int m_index = 0;
- bool m_isDefault = false;
- QString m_installationPath;
- QString m_documentPath;
};
QT_END_NAMESPACE_AM
diff --git a/src/application-lib/packageinfo.cpp b/src/application-lib/packageinfo.cpp
new file mode 100644
index 00000000..dc6813d2
--- /dev/null
+++ b/src/application-lib/packageinfo.cpp
@@ -0,0 +1,314 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QDataStream>
+#include <QBuffer>
+
+#include "packageinfo.h"
+#include "applicationinfo.h"
+#include "intentinfo.h"
+#include "exception.h"
+#include "installationreport.h"
+#include "yamlpackagescanner.h"
+
+
+QT_BEGIN_NAMESPACE_AM
+
+PackageInfo::PackageInfo()
+{ }
+
+PackageInfo::~PackageInfo()
+{
+ qDeleteAll(m_intents);
+ qDeleteAll(m_applications);
+}
+
+void PackageInfo::validate() const Q_DECL_NOEXCEPT_EXPR(false)
+{
+ QString errorMsg;
+ if (!isValidApplicationId(id(), &errorMsg))
+ throw Exception(Error::Parse, "the identifier (%1) is not a valid package-id: %2").arg(id()).arg(errorMsg);
+
+ if (m_applications.isEmpty())
+ throw Exception(Error::Parse, "package contains no applications");
+
+ for (const auto &app : m_applications) {
+ if (!isValidApplicationId(app->id(), &errorMsg))
+ throw Exception(Error::Parse, "the identifier (%1) is not a valid application-id: %2").arg(app->id()).arg(errorMsg);
+
+ if (app->codeFilePath().isEmpty())
+ throw Exception(Error::Parse, "the 'code' field must not be empty on application %1").arg(app->id());
+
+ if (app->runtimeName().isEmpty())
+ throw Exception(Error::Parse, "the 'runtimeName' field must not be empty on application %1").arg(app->id());
+ }
+}
+
+QString PackageInfo::id() const
+{
+ return m_id;
+}
+
+QMap<QString, QString> PackageInfo::names() const
+{
+ return m_names;
+}
+
+QString PackageInfo::name(const QString &language) const
+{
+ return m_names.value(language);
+}
+
+QMap<QString, QString> PackageInfo::descriptions() const
+{
+ return m_descriptions;
+}
+
+QString PackageInfo::description(const QString &language) const
+{
+ return m_descriptions.value(language);
+}
+
+QString PackageInfo::icon() const
+{
+ return m_icon;
+}
+
+QStringList PackageInfo::categories() const
+{
+ return m_categories;
+}
+
+bool PackageInfo::isBuiltIn() const
+{
+ return m_builtIn;
+}
+
+void PackageInfo::setBuiltIn(bool builtIn)
+{
+ m_builtIn = builtIn;
+}
+
+QString PackageInfo::version() const
+{
+ return m_version;
+}
+
+QVariantMap PackageInfo::dltConfiguration() const
+{
+ return m_dltConfiguration;
+}
+
+const QDir &PackageInfo::baseDir() const
+
+{
+ return m_baseDir;
+}
+
+void PackageInfo::setBaseDir(const QDir &dir)
+{
+ m_baseDir = dir;
+}
+
+QVector<ApplicationInfo *> PackageInfo::applications() const
+{
+ return m_applications;
+}
+
+QVector<IntentInfo *> PackageInfo::intents() const
+{
+ return m_intents;
+}
+
+const InstallationReport *PackageInfo::installationReport() const
+{
+ return m_installationReport.data();
+}
+
+void PackageInfo::setInstallationReport(InstallationReport *report)
+{
+ m_installationReport.reset(report);
+}
+
+void PackageInfo::writeToDataStream(QDataStream &ds) const
+{
+ QByteArray serializedReport;
+
+ if (auto report = installationReport()) {
+ QBuffer buffer(&serializedReport);
+ buffer.open(QBuffer::WriteOnly);
+ report->serialize(&buffer);
+ }
+
+ ds << m_id
+ << m_names
+ << m_icon
+ << m_descriptions
+ << m_categories
+ << m_version
+ << m_builtIn
+ << m_uid
+ << m_dltConfiguration
+ << m_baseDir.absolutePath()
+ << serializedReport;
+
+ ds << m_applications.size();
+ for (const auto &app : m_applications)
+ app->writeToDataStream(ds);
+
+ ds << m_intents.size();
+ for (const auto &intent : m_intents)
+ intent->writeToDataStream(ds);
+}
+
+PackageInfo *PackageInfo::readFromDataStream(QDataStream &ds)
+{
+ QScopedPointer<PackageInfo> pkg(new PackageInfo);
+
+ QString baseDir;
+ QByteArray serializedReport;
+
+ ds >> pkg->m_id
+ >> pkg->m_names
+ >> pkg->m_icon
+ >> pkg->m_descriptions
+ >> pkg->m_categories
+ >> pkg->m_version
+ >> pkg->m_builtIn
+ >> pkg->m_uid
+ >> pkg->m_dltConfiguration
+ >> baseDir
+ >> serializedReport;
+
+ pkg->m_baseDir.setPath(baseDir);
+
+ if (!serializedReport.isEmpty()) {
+ QBuffer buffer(&serializedReport);
+ buffer.open(QBuffer::ReadOnly);
+ pkg->m_installationReport.reset(new InstallationReport(pkg->id()));
+ try {
+ pkg->m_installationReport->deserialize(&buffer);
+ } catch (...) {
+ pkg->m_installationReport.reset();
+ }
+ }
+
+ int applicationsSize;
+ ds >> applicationsSize;
+ while (--applicationsSize >= 0)
+ pkg->m_applications << ApplicationInfo::readFromDataStream(pkg.data(), ds);
+
+ int intentsSize;
+ ds >> intentsSize;
+ while (--intentsSize >= 0)
+ pkg->m_intents << IntentInfo::readFromDataStream(pkg.data(), ds);
+
+ return pkg.take();
+}
+
+bool PackageInfo::isValidApplicationId(const QString &appId, QString *errorString)
+{
+ // we need to make sure that we can use the name as directory in a filesystem and inode names
+ // are limited to 255 characters in Linux. We need to subtract a safety margin for prefixes
+ // or suffixes though:
+ static const int maxLength = 150;
+
+ try {
+ if (appId.isEmpty())
+ throw Exception(Error::Parse, "must not be empty");
+
+ if (appId.length() > maxLength)
+ throw Exception(Error::Parse, "the maximum length is %1 characters (found %2 characters)").arg(maxLength, appId.length());
+
+ // all characters need to be ASCII minus any filesystem special characters:
+ bool spaceOnly = true;
+ static const char forbiddenChars[] = "<>:\"/\\|?*";
+ for (int pos = 0; pos < appId.length(); ++pos) {
+ ushort ch = appId.at(pos).unicode();
+ if ((ch < 0x20) || (ch > 0x7f) || strchr(forbiddenChars, ch & 0xff)) {
+ throw Exception(Error::Parse, "must consist of printable ASCII characters only, except any of \'%1'")
+ .arg(QString::fromLatin1(forbiddenChars));
+ }
+ if (spaceOnly)
+ spaceOnly = QChar(ch).isSpace();
+ }
+ if (spaceOnly)
+ throw Exception(Error::Parse, "must not consist of only white-space characters");
+
+ return true;
+ } catch (const Exception &e) {
+ if (errorString)
+ *errorString = e.errorString();
+ return false;
+ }
+}
+
+bool PackageInfo::isValidIcon(const QString &icon, QString *errorString)
+{
+ try {
+ if (icon.isEmpty())
+ throw Exception("empty path");
+
+ QFileInfo fileInfo(icon);
+
+ if (fileInfo.fileName() != icon)
+ throw Exception("'%1' is not a valid file name").arg(icon);
+
+ return true;
+ } catch (const Exception &e) {
+ if (errorString)
+ *errorString = e.errorString();
+ return false;
+ }
+}
+
+QString PackageInfo::manifestPath() const
+{
+ return m_baseDir.filePath(m_manifestName);
+}
+
+PackageInfo *PackageInfo::fromManifest(const QString &manifestPath)
+{
+ return YamlPackageScanner().scan(manifestPath);
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/application-lib/packageinfo.h b/src/application-lib/packageinfo.h
new file mode 100644
index 00000000..dc1708e1
--- /dev/null
+++ b/src/application-lib/packageinfo.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QDir>
+#include <QMap>
+#include <QString>
+#include <QStringList>
+#include <QVariantMap>
+#include <QVector>
+
+#include <QtAppManCommon/global.h>
+
+QT_FORWARD_DECLARE_CLASS(QDataStream)
+
+class tst_Application;
+
+QT_BEGIN_NAMESPACE_AM
+
+class InstallationReport;
+class IntentInfo;
+class ApplicationInfo;
+class YamlPackageScanner;
+
+class PackageInfo
+{
+public:
+ ~PackageInfo();
+
+ void validate() const Q_DECL_NOEXCEPT_EXPR(false);
+
+ QString id() const;
+
+ QMap<QString, QString> names() const;
+ QString name(const QString &language) const;
+ QMap<QString, QString> descriptions() const;
+ QString description(const QString &language) const;
+ QString icon() const;
+ QStringList categories() const;
+
+ bool isBuiltIn() const;
+ void setBuiltIn(bool builtIn);
+ QString version() const;
+ QVariantMap dltConfiguration() const;
+ uint uid() const { return m_uid; }
+
+ const QDir &baseDir() const;
+ void setBaseDir(const QDir &dir);
+
+ QVector<ApplicationInfo *> applications() const;
+ QVector<IntentInfo *> intents() const;
+
+ const InstallationReport *installationReport() const;
+ void setInstallationReport(InstallationReport *report);
+
+ void writeToDataStream(QDataStream &ds) const;
+ static PackageInfo *readFromDataStream(QDataStream &ds);
+
+ static bool isValidApplicationId(const QString &appId, QString *errorString = nullptr);
+ static bool isValidIcon(const QString &icon, QString *errorString = nullptr);
+
+ QString manifestPath() const;
+
+ static PackageInfo *fromManifest(const QString &manifestPath);
+
+private:
+ PackageInfo();
+
+ QString m_manifestName;
+ QString m_id;
+ QMap<QString, QString> m_names; // language -> name
+ QMap<QString, QString> m_descriptions; // language -> description
+ QStringList m_categories;
+ QString m_icon; // relative to info.json location
+ QString m_version;
+ bool m_builtIn = false; // system package - not removable
+ uint m_uid = uint(-1); // unix user id - move to installationReport
+ QVariantMap m_dltConfiguration;
+ QVector<ApplicationInfo *> m_applications;
+ QVector<IntentInfo *> m_intents;
+
+ // added by installer
+ QScopedPointer<InstallationReport> m_installationReport;
+ QDir m_baseDir;
+
+ friend class YamlPackageScanner;
+ friend class InstallationTask;
+ Q_DISABLE_COPY(PackageInfo)
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/application-lib/applicationscanner.h b/src/application-lib/packagescanner.h
index 5124d5c7..43d921bc 100644
--- a/src/application-lib/applicationscanner.h
+++ b/src/application-lib/packagescanner.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -44,26 +45,25 @@
#include <QtAppManCommon/global.h>
+QT_FORWARD_DECLARE_CLASS(QIODevice)
+
QT_BEGIN_NAMESPACE_AM
-class ApplicationInfo;
-class ApplicationAliasInfo;
+class PackageInfo;
-class ApplicationScanner
+class PackageScanner
{
public:
- virtual ~ApplicationScanner() = default;
-
- virtual ApplicationInfo *scan(const QString &filePath) Q_DECL_NOEXCEPT_EXPR(false) = 0;
- virtual ApplicationAliasInfo *scanAlias(const QString &filePath, const ApplicationInfo *application) Q_DECL_NOEXCEPT_EXPR(false) = 0;
+ virtual ~PackageScanner() = default;
- virtual QString metaDataFileName() const = 0;
+ virtual PackageInfo *scan(const QString &fileName) Q_DECL_NOEXCEPT_EXPR(false) = 0;
+ virtual PackageInfo *scan(QIODevice *source, const QString &fileName) Q_DECL_NOEXCEPT_EXPR(false) = 0;
protected:
- ApplicationScanner() = default;
+ PackageScanner() = default;
private:
- Q_DISABLE_COPY(ApplicationScanner)
+ Q_DISABLE_COPY(PackageScanner)
};
QT_END_NAMESPACE_AM
diff --git a/src/application-lib/yamlapplicationscanner.cpp b/src/application-lib/yamlapplicationscanner.cpp
deleted file mode 100644
index c3fd8e02..00000000
--- a/src/application-lib/yamlapplicationscanner.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Luxoft Sweden AB
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Luxoft Application Manager.
-**
-** $QT_BEGIN_LICENSE:LGPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** 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-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: LGPL-3.0
-**
-****************************************************************************/
-
-#include <QJsonDocument>
-#include <QJsonParseError>
-#include <QJsonObject>
-#include <QJsonArray>
-#include <QFile>
-#include <QFileInfo>
-#include <QScopedPointer>
-
-#include "global.h"
-#include "qtyaml.h"
-#include "exception.h"
-#include "applicationinfo.h"
-#include "yamlapplicationscanner.h"
-#include "utilities.h"
-
-QT_BEGIN_NAMESPACE_AM
-
-YamlApplicationScanner::YamlApplicationScanner()
-{ }
-
-ApplicationInfo *YamlApplicationScanner::scan(const QString &filePath) Q_DECL_NOEXCEPT_EXPR(false)
-{
- return static_cast<ApplicationInfo*>(scanInternal(filePath, false, nullptr));
-}
-
-ApplicationAliasInfo *YamlApplicationScanner::scanAlias(const QString &filePath,
- const ApplicationInfo *application) Q_DECL_NOEXCEPT_EXPR(false)
-{
- return static_cast<ApplicationAliasInfo*>(scanInternal(filePath, true, application));
-}
-
-AbstractApplicationInfo *YamlApplicationScanner::scanInternal(const QString &filePath, bool scanAlias,
- const ApplicationInfo *application) Q_DECL_NOEXCEPT_EXPR(false)
-{
- try {
- if (scanAlias && !application)
- throw Exception("cannot scan an alias without a valid base application");
-
- QFile f(filePath);
- if (!f.open(QIODevice::ReadOnly))
- throw Exception(f, "could not open file for reading");
-
- QtYaml::ParseError parseError;
- QVector<QVariant> docs = QtYaml::variantDocumentsFromYaml(f.readAll(), &parseError);
-
- if (parseError.error != QJsonParseError::NoError) {
- throw Exception(Error::IO, "YAML parse error at line %1, column %2: %3")
- .arg(parseError.line).arg(parseError.column).arg(parseError.errorString());
- }
-
- try {
- checkYamlFormat(docs, 2 /*number of expected docs*/, { "am-application", "am-application-alias" }, 1);
- } catch (const Exception &e) {
- throw Exception(Error::Parse, "not a valid YAML application meta-data file: %1").arg(e.errorString());
- }
-
- const auto header = docs.constFirst().toMap();
- bool isApp = (header.value(qSL("formatType")).toString() == qL1S("am-application"));
- bool isAlias = (header.value(qSL("formatType")).toString() == qL1S("am-application-alias"));
-
- if (!isApp && !isAlias)
- throw Exception(Error::Parse, "not a valid YAML application manifest");
- if (isAlias && !scanAlias)
- throw Exception(Error::Parse, "is an alias, but expected a normal manifest");
- if (!isAlias && scanAlias)
- throw Exception(Error::Parse, "is an not alias, although expected such a manifest");
-
- QScopedPointer<AbstractApplicationInfo> app;
- if (isAlias)
- app.reset(new ApplicationAliasInfo);
- else {
- app.reset(new ApplicationInfo);
- auto *appInfo = static_cast<ApplicationInfo*>(app.data());
- appInfo->m_manifestDir = QFileInfo(f).absoluteDir();
- appInfo->m_codeDir.setPath(appInfo->manifestDir());
- }
-
- QVariantMap yaml = docs.at(1).toMap();
- for (auto it = yaml.constBegin(); it != yaml.constEnd(); ++it) {
- QByteArray field = it.key().toLatin1();
- bool unknownField = false;
- const QVariant &v = it.value();
-
- if ((!isAlias && (field == "id"))
- || (isAlias && (field == "aliasId"))) {
- app->m_id = v.toString();
- if (isAlias) {
- int sepPos = app->m_id.indexOf(qL1C('@'));
- if (sepPos < 0 || sepPos == (app->m_id.size() - 1))
- throw Exception(Error::Parse, "malformed aliasId '%1'").arg(app->m_id);
- QString realId = app->m_id.left(sepPos);
- if (application->id() != realId) {
- throw Exception(Error::Parse, "aliasId '%1' does not match base application id '%2'")
- .arg(app->m_id, application->id());
- }
- }
- } else if (field == "icon") {
- app->m_icon = v.toString();
- } else if (field == "name") {
- auto nameMap = v.toMap();
- for (auto it = nameMap.constBegin(); it != nameMap.constEnd(); ++it)
- app->m_name.insert(it.key(), it.value().toString());
- } else if (field == "documentUrl") {
- app->m_documentUrl = v.toString();
- } else if (!isAlias) {
- auto *appInfo = static_cast<ApplicationInfo*>(app.data());
- if (field == "code") {
- appInfo->m_codeFilePath = v.toString();
- } else if (field == "runtime") {
- appInfo->m_runtimeName = v.toString();
- } else if (field == "runtimeParameters") {
- appInfo->m_runtimeParameters = v.toMap();
- } else if (field == "supportsApplicationInterface") {
- appInfo->m_supportsApplicationInterface = v.toBool();
- } else if (field == "capabilities") {
- appInfo->m_capabilities = variantToStringList(v);
- appInfo->m_capabilities.sort();
- } else if (field == "categories") {
- appInfo->m_categories = variantToStringList(v);
- appInfo->m_categories.sort();
- } else if (field == "mimeTypes") {
- appInfo->m_mimeTypes = variantToStringList(v);
- appInfo->m_mimeTypes.sort();
- } else if (field == "applicationProperties") {
- const QVariantMap rawMap = v.toMap();
- appInfo->m_sysAppProperties = rawMap.value(qSL("protected")).toMap();
- appInfo->m_allAppProperties = appInfo->m_sysAppProperties;
- const QVariantMap pri = rawMap.value(qSL("private")).toMap();
- for (auto it = pri.cbegin(); it != pri.cend(); ++it)
- appInfo->m_allAppProperties.insert(it.key(), it.value());
- } else if (field == "version") {
- appInfo->m_version = v.toString();
- } else if (field == "opengl") {
- appInfo->m_openGLConfiguration = v.toMap();
-
- // sanity check
- static QStringList validKeys = {
- qSL("desktopProfile"),
- qSL("esMajorVersion"),
- qSL("esMinorVersion")
- };
- for (auto it = appInfo->m_openGLConfiguration.cbegin();
- it != appInfo->m_openGLConfiguration.cend(); ++it) {
- if (!validKeys.contains(it.key())) {
- throw Exception(Error::Parse, "the 'opengl' object contains the unsupported key '%1'")
- .arg(it.key());
- }
- }
- } else if (field == "logging") {
- const QVariantMap logging = v.toMap();
- if (!logging.isEmpty()) {
- if (logging.size() > 1 || logging.firstKey() != qSL("dlt"))
- throw Exception(Error::Parse, "'logging' only supports the 'dlt' key");
- appInfo->m_dlt = logging.value(qSL("dlt")).toMap();
-
- // sanity check
- for (auto it = appInfo->m_dlt.cbegin(); it != appInfo->m_dlt.cend(); ++it) {
- if (it.key() != qSL("id") && it.key() != qSL("description"))
- throw Exception(Error::Parse, "unsupported key in 'logging/dlt'");
- }
- }
- } else if (field == "intents") {
- appInfo->m_intents = v.toList();
- } else {
- unknownField = true;
- }
- } else {
- unknownField = true;
- }
- if (unknownField)
- throw Exception(Error::Parse, "contains unsupported field: '%1'").arg(field);
- }
-
- app->validate();
- return app.take();
- } catch (const Exception &e) {
- throw Exception(e.errorCode(), "Failed to parse manifest file %1: %2").arg(filePath, e.errorString());
- }
-}
-
-
-QString YamlApplicationScanner::metaDataFileName() const
-{
- return qSL("info.yaml");
-}
-
-QT_END_NAMESPACE_AM
diff --git a/src/application-lib/yamlapplicationscanner.h b/src/application-lib/yamlapplicationscanner.h
deleted file mode 100644
index fd667182..00000000
--- a/src/application-lib/yamlapplicationscanner.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Luxoft Sweden AB
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Luxoft Application Manager.
-**
-** $QT_BEGIN_LICENSE:LGPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** 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-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: LGPL-3.0
-**
-****************************************************************************/
-
-#pragma once
-
-#include <QtAppManApplication/applicationscanner.h>
-
-QT_BEGIN_NAMESPACE_AM
-
-class AbstractApplicationInfo;
-
-class YamlApplicationScanner : public ApplicationScanner
-{
-public:
- YamlApplicationScanner();
-
- ApplicationInfo *scan(const QString &filePath) Q_DECL_NOEXCEPT_EXPR(false) override;
- ApplicationAliasInfo *scanAlias(const QString &filePath,
- const ApplicationInfo *application) Q_DECL_NOEXCEPT_EXPR(false) override;
-
- QString metaDataFileName() const override;
-
-private:
- AbstractApplicationInfo *scanInternal(const QString &filePath, bool scanAlias,
- const ApplicationInfo *application) Q_DECL_NOEXCEPT_EXPR(false);
-};
-
-QT_END_NAMESPACE_AM
diff --git a/src/application-lib/yamlpackagescanner.cpp b/src/application-lib/yamlpackagescanner.cpp
new file mode 100644
index 00000000..f6a569fe
--- /dev/null
+++ b/src/application-lib/yamlpackagescanner.cpp
@@ -0,0 +1,359 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QJsonDocument>
+#include <QJsonParseError>
+#include <QJsonObject>
+#include <QJsonArray>
+#include <QFile>
+#include <QFileInfo>
+#include <QScopedPointer>
+
+#include "global.h"
+#include "qtyaml.h"
+#include "exception.h"
+#include "logging.h"
+#include "packageinfo.h"
+#include "applicationinfo.h"
+#include "intentinfo.h"
+#include "yamlpackagescanner.h"
+#include "utilities.h"
+
+QT_BEGIN_NAMESPACE_AM
+
+YamlPackageScanner::YamlPackageScanner()
+{ }
+
+PackageInfo *YamlPackageScanner::scan(const QString &fileName) Q_DECL_NOEXCEPT_EXPR(false)
+{
+ QFile f(fileName);
+ if (!f.open(QIODevice::ReadOnly))
+ throw Exception(f, "Cannot open for reading");
+ return scan(&f, f.fileName());
+}
+
+PackageInfo *YamlPackageScanner::scan(QIODevice *source, const QString &fileName) Q_DECL_NOEXCEPT_EXPR(false)
+{
+ try {
+ YamlParser p(source->readAll());
+
+ bool legacy = false;
+ try {
+ auto header = p.parseHeader();
+ if (header.first == qL1S("am-application") && header.second == 1)
+ legacy = true;
+ else if (!(header.first == qL1S("am-package") && header.second == 1))
+ throw Exception("Unsupported format type and/or version");
+ p.nextDocument();
+ } catch (const Exception &e) {
+ throw YamlParserException(&p, "not a valid YAML package meta-data file: %1").arg(e.errorString());
+ }
+
+ QStringList appIds; // duplicate check
+ QScopedPointer<PackageInfo> pkgInfo(new PackageInfo);
+ if (!fileName.isEmpty()) {
+ QFileInfo fi(fileName);
+ pkgInfo->m_baseDir = fi.absoluteDir();
+ pkgInfo->m_manifestName = fi.fileName();
+ }
+
+ QScopedPointer<ApplicationInfo> legacyAppInfo(legacy ? new ApplicationInfo(pkgInfo.data()) : nullptr);
+
+ // ----------------- package -----------------
+
+ YamlParser::Fields fields;
+ fields.emplace_back("id", true, YamlParser::Scalar, [&pkgInfo, &legacyAppInfo](YamlParser *p) {
+ QString id = p->parseString();
+ if (id.isEmpty())
+ throw YamlParserException(p, "packages need to have an id");
+ pkgInfo->m_id = id;
+ if (legacyAppInfo)
+ legacyAppInfo->m_id = pkgInfo->id();
+ });
+ fields.emplace_back("icon", true, YamlParser::Scalar, [&pkgInfo](YamlParser *p) {
+ pkgInfo->m_icon = p->parseString();
+ });
+ fields.emplace_back("name", true, YamlParser::Map, [&pkgInfo](YamlParser *p) {
+ auto nameMap = p->parseMap();
+ for (auto it = nameMap.constBegin(); it != nameMap.constEnd(); ++it)
+ pkgInfo->m_names.insert(it.key(), it.value().toString());
+
+ if (pkgInfo->m_names.isEmpty())
+ throw YamlParserException(p, "the 'name' field must not be empty");
+ });
+ if (!legacy) {
+ fields.emplace_back("description", false, YamlParser::Map, [&pkgInfo](YamlParser *p) {
+ auto descriptionMap = p->parseMap();
+ for (auto it = descriptionMap.constBegin(); it != descriptionMap.constEnd(); ++it)
+ pkgInfo->m_descriptions.insert(it.key(), it.value().toString());
+ });
+ }
+ fields.emplace_back("categories", false, YamlParser::Scalar | YamlParser::List, [&pkgInfo](YamlParser *p) {
+ pkgInfo->m_categories = p->parseStringOrStringList();
+ pkgInfo->m_categories.sort();
+ });
+ fields.emplace_back("version", false, YamlParser::Scalar, [&pkgInfo](YamlParser *p) {
+ pkgInfo->m_version = p->parseString();
+ });
+ fields.emplace_back("logging", false, YamlParser::Map, [&pkgInfo](YamlParser *p) {
+ const QVariantMap logging = p->parseMap();
+ if (!logging.isEmpty()) {
+ if (logging.size() > 1 || logging.firstKey() != qSL("dlt"))
+ throw YamlParserException(p, "'logging' only supports the 'dlt' key");
+ pkgInfo->m_dltConfiguration = logging.value(qSL("dlt")).toMap();
+
+ // sanity check
+ for (auto it = pkgInfo->m_dltConfiguration.cbegin(); it != pkgInfo->m_dltConfiguration.cend(); ++it) {
+ if (it.key() != qSL("id") && it.key() != qSL("description"))
+ throw YamlParserException(p, "unsupported key in 'logging/dlt'");
+ }
+ }
+ });
+ if (legacy) {
+ fields.emplace_back("code", true, YamlParser::Scalar, [&legacyAppInfo](YamlParser *p) {
+ legacyAppInfo->m_codeFilePath = p->parseString();
+ });
+ fields.emplace_back("runtime", true, YamlParser::Scalar, [&legacyAppInfo](YamlParser *p) {
+ legacyAppInfo->m_runtimeName = p->parseString();
+ });
+ fields.emplace_back("runtimeParameters", false, YamlParser::Map, [&legacyAppInfo](YamlParser *p) {
+ legacyAppInfo->m_runtimeParameters = p->parseMap();
+ });
+ fields.emplace_back("supportsApplicationInterface", false, YamlParser::Scalar, [&legacyAppInfo](YamlParser *p) {
+ legacyAppInfo->m_supportsApplicationInterface = p->parseScalar().toBool();
+ });
+ fields.emplace_back("capabilities", false, YamlParser::Scalar | YamlParser::List, [&legacyAppInfo](YamlParser *p) {
+ legacyAppInfo->m_capabilities = p->parseStringOrStringList();
+ legacyAppInfo->m_capabilities.sort();
+ });
+ fields.emplace_back("opengl", false, YamlParser::Map, [&legacyAppInfo](YamlParser *p) {
+ legacyAppInfo->m_openGLConfiguration = p->parseMap();
+
+ // sanity check - could be rewritten using the "fields" mechanism
+ static QStringList validKeys = {
+ qSL("desktopProfile"),
+ qSL("esMajorVersion"),
+ qSL("esMinorVersion")
+ };
+ for (auto it = legacyAppInfo->m_openGLConfiguration.cbegin();
+ it != legacyAppInfo->m_openGLConfiguration.cend(); ++it) {
+ if (!validKeys.contains(it.key())) {
+ throw YamlParserException(p, "the 'opengl' object contains the unsupported key '%1'")
+ .arg(it.key());
+ }
+ }
+ });
+ fields.emplace_back("applicationProperties", false, YamlParser::Map, [&legacyAppInfo](YamlParser *p) {
+ const QVariantMap rawMap = p->parseMap();
+ legacyAppInfo->m_sysAppProperties = rawMap.value(qSL("protected")).toMap();
+ legacyAppInfo->m_allAppProperties = legacyAppInfo->m_sysAppProperties;
+ const QVariantMap pri = rawMap.value(qSL("private")).toMap();
+ for (auto it = pri.cbegin(); it != pri.cend(); ++it)
+ legacyAppInfo->m_allAppProperties.insert(it.key(), it.value());
+ });
+ fields.emplace_back("documentUrl", false, YamlParser::Scalar, [](YamlParser *p) {
+ qCDebug(LogSystem) << " ignoring 'documentUrl'";
+ (void) p->parseScalar();
+ });
+ fields.emplace_back("mimeTypes", false, YamlParser::Scalar | YamlParser::List, [&legacyAppInfo](YamlParser *p) {
+ legacyAppInfo->m_supportedMimeTypes = p->parseStringOrStringList();
+ legacyAppInfo->m_supportedMimeTypes.sort();
+ });
+ }
+
+ // ----------------- applications -----------------
+
+ if (!legacy) {
+ fields.emplace_back("applications", true, YamlParser::List, [&pkgInfo, &appIds](YamlParser *p) {
+ p->parseList([&pkgInfo, &appIds](YamlParser *p) {
+ QScopedPointer<ApplicationInfo> appInfo(new ApplicationInfo(pkgInfo.data()));
+ YamlParser::Fields appFields;
+
+ appFields.emplace_back("id", true, YamlParser::Scalar, [&appInfo, &appIds](YamlParser *p) {
+ QString id = p->parseString();
+ if (id.isEmpty())
+ throw YamlParserException(p, "applications need to have an id");
+ if (appIds.contains(id))
+ throw YamlParserException(p, "found two applications with the same id %1").arg(id);
+ appInfo->m_id = id;
+ });
+ appFields.emplace_back("code", true, YamlParser::Scalar, [&appInfo](YamlParser *p) {
+ appInfo->m_codeFilePath = p->parseString();
+ });
+ appFields.emplace_back("runtime", true, YamlParser::Scalar, [&appInfo](YamlParser *p) {
+ appInfo->m_runtimeName = p->parseString();
+ });
+ appFields.emplace_back("runtimeParameters", false, YamlParser::Map, [&appInfo](YamlParser *p) {
+ appInfo->m_runtimeParameters = p->parseMap();
+ });
+ appFields.emplace_back("supportsApplicationInterface", false, YamlParser::Scalar, [&appInfo](YamlParser *p) {
+ appInfo->m_supportsApplicationInterface = p->parseScalar().toBool();
+ });
+ appFields.emplace_back("capabilities", false, YamlParser::Scalar | YamlParser::List, [&appInfo](YamlParser *p) {
+ appInfo->m_capabilities = p->parseStringOrStringList();
+ appInfo->m_capabilities.sort();
+ });
+ appFields.emplace_back("opengl", false, YamlParser::Map, [&appInfo](YamlParser *p) {
+ appInfo->m_openGLConfiguration = p->parseMap();
+
+ // sanity check - could be rewritten using the "fields" mechanism
+ static QStringList validKeys = {
+ qSL("desktopProfile"),
+ qSL("esMajorVersion"),
+ qSL("esMinorVersion")
+ };
+ for (auto it = appInfo->m_openGLConfiguration.cbegin();
+ it != appInfo->m_openGLConfiguration.cend(); ++it) {
+ if (!validKeys.contains(it.key())) {
+ throw YamlParserException(p, "the 'opengl' object contains the unsupported key '%1'")
+ .arg(it.key());
+ }
+ }
+ });
+ appFields.emplace_back("applicationProperties", false, YamlParser::Map, [&appInfo](YamlParser *p) {
+ const QVariantMap rawMap = p->parseMap();
+ appInfo->m_sysAppProperties = rawMap.value(qSL("protected")).toMap();
+ appInfo->m_allAppProperties = appInfo->m_sysAppProperties;
+ const QVariantMap pri = rawMap.value(qSL("private")).toMap();
+ for (auto it = pri.cbegin(); it != pri.cend(); ++it)
+ appInfo->m_allAppProperties.insert(it.key(), it.value());
+ });
+
+ p->parseFields(appFields);
+ appIds << appInfo->id();
+ pkgInfo->m_applications << appInfo.take();
+ });
+ });
+ }
+
+ // ----------------- intents -----------------
+
+ fields.emplace_back("intents", false, YamlParser::List, [&pkgInfo, &appIds, legacy](YamlParser *p) {
+ QStringList intentIds; // duplicate check
+ p->parseList([&pkgInfo, &appIds, &intentIds, legacy](YamlParser *p) {
+ QScopedPointer<IntentInfo> intentInfo(new IntentInfo(pkgInfo.data()));
+ YamlParser::Fields intentFields;
+
+ intentFields.emplace_back("id", true, YamlParser::Scalar, [&intentInfo, &intentIds, &pkgInfo](YamlParser *p) {
+ QString id = p->parseString();
+ if (id.isEmpty())
+ throw YamlParserException(p, "intents need to have an id (package %1)").arg(pkgInfo->id());
+ if (intentIds.contains(id))
+ throw YamlParserException(p, "found two intent handlers for intent %2 (package %1)").arg(pkgInfo->id()).arg(id);
+ intentInfo->m_id = id;
+ });
+ intentFields.emplace_back("visibility", false, YamlParser::Scalar, [&intentInfo](YamlParser *p) {
+ const QString visibilityStr = p->parseString();
+ if (visibilityStr == qL1S("private")) {
+ intentInfo->m_visibility = IntentInfo::Private;
+ } else if (visibilityStr != qL1S("public")) {
+ throw YamlParserException(p, "intent visibilty '%2' is invalid on intent %1 (valid values are either 'public' or 'private'")
+ .arg(intentInfo->m_id).arg(visibilityStr);
+ }
+ });
+ intentFields.emplace_back(legacy ? "handledBy" : "handlingApplicationId", false, YamlParser::Scalar, [&intentInfo, &appIds](YamlParser *p) {
+ QString appId = p->parseString();
+ if (appIds.contains(appId)) {
+ intentInfo->m_handlingApplicationId = appId;
+ } else {
+ throw YamlParserException(p, "the 'handlingApplicationId' field on intent %1 points to the unknown application id %2")
+ .arg(intentInfo->m_id).arg(appId);
+ }
+ });
+ intentFields.emplace_back("requiredCapabilities", false, YamlParser::Scalar | YamlParser::List, [&intentInfo](YamlParser *p) {
+ intentInfo->m_requiredCapabilities = p->parseStringOrStringList();
+ });
+ intentFields.emplace_back("parameterMatch", false, YamlParser::Map, [&intentInfo](YamlParser *p) {
+ intentInfo->m_parameterMatch = p->parseMap();
+ });
+ intentFields.emplace_back("icon", false, YamlParser::Scalar, [&intentInfo](YamlParser *p) {
+ intentInfo->m_icon = p->parseString();
+ });
+ intentFields.emplace_back("name", false, YamlParser::Map, [&intentInfo](YamlParser *p) {
+ auto nameMap = p->parseMap();
+ for (auto it = nameMap.constBegin(); it != nameMap.constEnd(); ++it)
+ intentInfo->m_names.insert(it.key(), it.value().toString());
+ });
+ intentFields.emplace_back("description", false, YamlParser::Map, [&intentInfo](YamlParser *p) {
+ auto descriptionMap = p->parseMap();
+ for (auto it = descriptionMap.constBegin(); it != descriptionMap.constEnd(); ++it)
+ intentInfo->m_descriptions.insert(it.key(), it.value().toString());
+ });
+ intentFields.emplace_back("categories", false, YamlParser::Scalar | YamlParser::List, [&intentInfo](YamlParser *p) {
+ intentInfo->m_categories = p->parseStringOrStringList();
+ intentInfo->m_categories.sort();
+ });
+
+ p->parseFields(intentFields);
+
+ if (intentInfo->handlingApplicationId().isEmpty()) {
+ if (legacy) {
+ intentInfo->m_handlingApplicationId = pkgInfo->id();
+ } else if (pkgInfo->m_applications.count() == 1) {
+ intentInfo->m_handlingApplicationId = pkgInfo->m_applications.constFirst()->id();
+ } else {
+ throw Exception(Error::Parse, "a 'handlingApplicationId' field on intent %1 is needed if more than one application is defined")
+ .arg(intentInfo->m_id);
+ }
+ }
+
+ pkgInfo->m_intents << intentInfo.take();
+ });
+ });
+
+ p.parseFields(fields);
+
+ if (legacy)
+ pkgInfo->m_applications << legacyAppInfo.take();
+
+ // validate the ids, runtime names and all referenced files
+ pkgInfo->validate();
+ return pkgInfo.take();
+ } catch (const Exception &e) {
+ throw Exception(e.errorCode(), "Failed to parse manifest file %1: %2")
+ .arg(!fileName.isEmpty() ? QDir().relativeFilePath(fileName) : qSL("<stream>"), e.errorString());
+ }
+}
+
+
+QT_END_NAMESPACE_AM
diff --git a/src/application-lib/yamlpackagescanner.h b/src/application-lib/yamlpackagescanner.h
new file mode 100644
index 00000000..67b8ef91
--- /dev/null
+++ b/src/application-lib/yamlpackagescanner.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QIODevice>
+#include <QtAppManApplication/packagescanner.h>
+
+QT_BEGIN_NAMESPACE_AM
+
+
+class YamlPackageScanner : public PackageScanner
+{
+public:
+ YamlPackageScanner();
+
+ PackageInfo *scan(const QString &filePath) Q_DECL_NOEXCEPT_EXPR(false) override;
+ PackageInfo *scan(QIODevice *source, const QString &filePath) Q_DECL_NOEXCEPT_EXPR(false) override;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/common-lib/common-lib.pro b/src/common-lib/common-lib.pro
index f3f99251..4d0e3efa 100644
--- a/src/common-lib/common-lib.pro
+++ b/src/common-lib/common-lib.pro
@@ -30,6 +30,7 @@ SOURCES += \
crashhandler.cpp \
logging.cpp \
dbus-utilities.cpp \
+ configcache.cpp
qtHaveModule(qml):SOURCES += \
qml-utilities.cpp \
@@ -44,7 +45,9 @@ HEADERS += \
unixsignalhandler.h \
processtitle.h \
crashhandler.h \
- logging.h
+ logging.h \
+ configcache.h \
+ configcache_p.h
qtHaveModule(qml):HEADERS += \
qml-utilities.h \
diff --git a/src/common-lib/configcache.cpp b/src/common-lib/configcache.cpp
new file mode 100644
index 00000000..aab695e4
--- /dev/null
+++ b/src/common-lib/configcache.cpp
@@ -0,0 +1,414 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QDebug>
+#include <QFile>
+#include <QFileInfo>
+#include <QStandardPaths>
+#include <QDataStream>
+#include <QCryptographicHash>
+#include <QElapsedTimer>
+#include <QBuffer>
+#include <QtConcurrent/QtConcurrent>
+
+#include "configcache.h"
+#include "configcache_p.h"
+#include "utilities.h"
+#include "exception.h"
+#include "logging.h"
+
+// use QtConcurrent to parse the files, if there are more than x files
+#define AM_PARALLEL_THRESHOLD 1
+
+
+QT_BEGIN_NAMESPACE_AM
+
+QDataStream &operator>>(QDataStream &ds, ConfigCacheEntry &ce)
+{
+ bool contentValid = false;
+ ds >> ce.filePath >> ce.checksum >> contentValid;
+ ce.rawContent.clear();
+ ce.content = contentValid ? reinterpret_cast<void *>(-1) : nullptr;
+ return ds;
+}
+
+QDataStream &operator<<(QDataStream &ds, const ConfigCacheEntry &ce)
+{
+ ds << ce.filePath << ce.checksum << static_cast<bool>(ce.content);
+ return ds;
+}
+
+QDataStream &operator>>(QDataStream &ds, CacheHeader &ch)
+{
+ ds >> ch.magic >> ch.version >> ch.globalId >> ch.baseName >> ch.entries;
+ return ds;
+}
+
+QDataStream &operator<<(QDataStream &ds, const CacheHeader &ch)
+{
+ ds << ch.magic << ch.version << ch.globalId << ch.baseName << ch.entries;
+ return ds;
+}
+
+QDebug operator<<(QDebug dbg, const ConfigCacheEntry &ce)
+{
+ dbg << "CacheEntry {\n " << ce.filePath << "\n " << ce.checksum.toHex() << "\n valid:"
+ << (ce.content ? "yes" : "no") << ce.content
+ << "\n}\n";
+ return dbg;
+}
+
+
+// this could be used in the future to have multiple AM instances that each have their own cache
+quint64 CacheHeader::s_globalId = 0;
+
+bool CacheHeader::isValid(const QString &baseName) const
+{
+ return magic == Magic
+ && version == Version
+ && globalId == s_globalId
+ && this->baseName == baseName
+ && entries < 1000;
+}
+
+
+AbstractConfigCache::AbstractConfigCache(const QStringList &configFiles, const QString &cacheBaseName, Options options)
+ : d(new ConfigCachePrivate)
+{
+ d->options = options;
+ d->rawFiles = configFiles;
+ d->cacheBaseName = cacheBaseName;
+}
+
+AbstractConfigCache::~AbstractConfigCache()
+{
+ // make sure that clear() was called in ~Cache(), since we need the virtual destruct() function!
+ delete d;
+}
+
+void *AbstractConfigCache::takeMergedResult() const
+{
+ Q_ASSERT(d->options & MergedResult);
+ void *result = d->mergedContent;
+ d->mergedContent = nullptr;
+ return result;
+}
+
+void *AbstractConfigCache::takeResult(int index) const
+{
+ Q_ASSERT(!(d->options & MergedResult));
+ void *result = nullptr;
+ if (index >= 0 && index < d->cache.size())
+ qSwap(result, d->cache[index].content);
+ return result;
+}
+
+void *AbstractConfigCache::takeResult(const QString &rawFile) const
+{
+ return takeResult(d->cacheIndex.value(rawFile, -1));
+}
+
+void AbstractConfigCache::parse(QStringList *warnings)
+{
+ clear();
+
+ if (d->rawFiles.isEmpty())
+ return;
+
+ QElapsedTimer timer;
+ if (LogCache().isDebugEnabled())
+ timer.start();
+
+ // normalize all yaml file names
+ QStringList rawFilePaths;
+ for (const auto &rawFile : d->rawFiles)
+ rawFilePaths << QFileInfo(rawFile).canonicalFilePath();
+
+ // find the correct cache location and make sure it exists
+ const QDir cacheLocation = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
+ if (!cacheLocation.exists())
+ cacheLocation.mkpath(qSL("."));
+ const QString cacheFilePath = cacheLocation.absoluteFilePath(qSL("appman-%1.cache").arg(d->cacheBaseName));
+ QFile cacheFile(cacheFilePath);
+
+ QAtomicInt cacheIsValid = false;
+ QAtomicInt cacheIsComplete = false;
+
+ QVector<ConfigCacheEntry> cache;
+ void *mergedContent = nullptr;
+
+ qCDebug(LogCache) << d->cacheBaseName << "cache file:" << cacheFilePath;
+ qCDebug(LogCache) << d->cacheBaseName << "use-cache:" << (d->options & NoCache ? "no" : "yes")
+ << "/ clear-cache:" << (d->options & ClearCache ? "yes" : "no");
+ qCDebug(LogCache) << d->cacheBaseName << "reading:" << rawFilePaths;
+
+ if (!d->options.testFlag(NoCache) && !d->options.testFlag(ClearCache)) {
+ if (cacheFile.open(QFile::ReadOnly)) {
+ try {
+ QDataStream ds(&cacheFile);
+ CacheHeader cacheHeader;
+ ds >> cacheHeader;
+
+ if (ds.status() != QDataStream::Ok)
+ throw Exception("failed to read cache header");
+ if (!cacheHeader.isValid(d->cacheBaseName))
+ throw Exception("failed to parse cache header");
+
+ cache.resize(int(cacheHeader.entries));
+ for (int i = 0; i < int(cacheHeader.entries); ++i) {
+ ConfigCacheEntry &ce = cache[i];
+ ds >> ce;
+ if (ce.content)
+ ce.content = loadFromCache(ds);
+ }
+ if (d->options & MergedResult) {
+ mergedContent = loadFromCache(ds);
+
+ if (!mergedContent)
+ throw Exception("failed to read merged cache content");
+ }
+
+ if (ds.status() != QDataStream::Ok)
+ throw Exception("failed to read cache content");
+
+ cacheIsValid = true;
+
+ qCDebug(LogCache) << d->cacheBaseName << "loaded" << cache.size() << "entries in"
+ << timer.nsecsElapsed() / 1000 << "usec";
+
+ // check if we can use the cache as-is, or if we need to cherry-pick parts
+ if (rawFilePaths.count() == cache.count()) {
+ for (int i = 0; i < rawFilePaths.count(); ++i) {
+ const ConfigCacheEntry &ce = cache.at(i);
+ if (rawFilePaths.at(i) != ce.filePath)
+ throw Exception("the cached file names do not match the current set (or their order changed)");
+ if (!mergedContent && !ce.content)
+ throw Exception("cache entry has invalid content");
+ }
+ cacheIsComplete = true;
+ }
+
+
+ } catch (const Exception &e) {
+ if (warnings)
+ *warnings << qL1S("Failed to read cache: ") + qL1S(e.what());
+ else
+ qWarning(LogCache) << "Failed to read cache:" << e.what();
+ }
+ }
+ } else if (d->options.testFlag(ClearCache)) {
+ cacheFile.remove();
+ }
+
+ qCDebug(LogCache) << d->cacheBaseName << "valid:" << (cacheIsValid ? "yes" : "no")
+ << "/ complete:" << (cacheIsComplete ? "yes" : "no");
+
+ if (!cacheIsComplete) {
+ // we need to pick the parts we can re-use
+
+ QVector<ConfigCacheEntry> newCache(rawFilePaths.size());
+
+ // we are iterating over n^2 entries in the worst case scenario -- we could reduce it to n
+ // by using a QHash or QMap, but that doesn't come for free either: especially given the
+ // low number of processed entries (well under 100 for app manifests; around a couple for
+ // config files)
+ for (int i = 0; i < rawFilePaths.size(); ++i) {
+ const QString &rawFilePath = rawFilePaths.at(i);
+ ConfigCacheEntry &ce = newCache[i];
+
+ // if we already got this file in the cache, then use the entry
+ bool found = false;
+ for (auto it = cache.cbegin(); it != cache.cend(); ++it) {
+ if (it->filePath == rawFilePath) {
+ ce = *it;
+ found = true;
+ qCDebug(LogCache) << d->cacheBaseName << "found cache entry for" << it->filePath;
+ break;
+ }
+ }
+
+ // if it's not yet cached, then add it to the list
+ if (!found) {
+ ce.filePath = rawFilePath;
+ qCDebug(LogCache) << d->cacheBaseName << "missing cache entry for" << rawFilePath;
+ }
+ }
+ cache = newCache;
+ }
+
+ // reads a single config file and calculates its hash - defined as lambda to be usable
+ // both via QtConcurrent and via std:for_each
+ auto readConfigFile = [&cacheIsComplete, &warnings, this](ConfigCacheEntry &ce) {
+ QFile file(ce.filePath);
+ if (!file.open(QIODevice::ReadOnly))
+ throw Exception("Failed to open file '%1' for reading.\n").arg(file.fileName());
+
+ if (file.size() > 1024*1024)
+ throw Exception("File '%1' is too big (> 1MB).\n").arg(file.fileName());
+
+ ce.rawContent = file.readAll();
+ preProcessSourceContent(ce.rawContent, ce.filePath);
+
+ QByteArray checksum = QCryptographicHash::hash(ce.rawContent, QCryptographicHash::Sha1);
+ ce.checksumMatches = (checksum == ce.checksum);
+ ce.checksum = checksum;
+ if (!ce.checksumMatches) {
+ if (ce.content) {
+ if (warnings)
+ *warnings << qL1S("Failed to read Cache: cached file checksums do not match");
+ else
+ qWarning(LogCache) << "Failed to read Cache: cached file checksums do not match";
+ destruct(ce.content);
+ ce.content = nullptr;
+ }
+ cacheIsComplete = false;
+ }
+ };
+
+ // these can throw
+ if (cache.size() > AM_PARALLEL_THRESHOLD)
+ QtConcurrent::blockingMap(cache, readConfigFile);
+ else
+ std::for_each(cache.begin(), cache.end(), readConfigFile);
+
+ qCDebug(LogCache) << d->cacheBaseName << "reading all of" << cache.size() << "file(s) finished after"
+ << (timer.nsecsElapsed() / 1000) << "usec";
+ qCDebug(LogCache) << d->cacheBaseName << "still complete:" << (cacheIsComplete ? "yes" : "no");
+
+ if (!cacheIsComplete && !rawFilePaths.isEmpty()) {
+ // we have read a partial cache or none at all - parse what's not cached yet
+ QAtomicInt count;
+
+ auto parseConfigFile = [this, &count](ConfigCacheEntry &ce) {
+ if (ce.content)
+ return;
+
+ ++count;
+ try {
+ QBuffer buffer(&ce.rawContent);
+ buffer.open(QIODevice::ReadOnly);
+ ce.content = loadFromSource(&buffer, ce.filePath);
+ } catch (const Exception &e) {
+ throw Exception("Could not parse file '%1': %2")
+ .arg(ce.filePath).arg(e.errorString());
+ }
+ };
+
+ // these can throw
+ if (cache.size() > AM_PARALLEL_THRESHOLD)
+ QtConcurrent::blockingMap(cache, parseConfigFile);
+ else
+ std::for_each(cache.begin(), cache.end(), parseConfigFile);
+
+ if (d->options & MergedResult) {
+ // we cannot parallelize this step, since subsequent config files can overwrite
+ // or append to values
+ mergedContent = cache.at(0).content;
+ cache[0].content = nullptr;
+ for (int i = 1; i < cache.size(); ++i) {
+ ConfigCacheEntry &ce = cache[i];
+ merge(mergedContent, ce.content);
+ destruct(ce.content);
+ ce.content = nullptr;
+ }
+ }
+
+ qCDebug(LogCache) << d->cacheBaseName << "parsing" << count.load() << "file(s) finished after"
+ << (timer.nsecsElapsed() / 1000) << "usec";
+
+ if (!d->options.testFlag(NoCache)) {
+ // everything is parsed now, so we can write a new cache file
+
+ try {
+ QFile cacheFile(cacheFilePath);
+ if (!cacheFile.open(QFile::WriteOnly | QFile::Truncate))
+ throw Exception(cacheFile, "failed to open file for writing");
+
+ QDataStream ds(&cacheFile);
+ CacheHeader cacheHeader;
+ cacheHeader.baseName = d->cacheBaseName;
+ cacheHeader.entries = quint32(cache.size());
+ ds << cacheHeader;
+
+ for (int i = 0; i < cache.size(); ++i) {
+ const ConfigCacheEntry &ce = cache.at(i);
+ ds << ce;
+ // qCDebug(LogCache) << "SAVING" << ce << ce.content;
+ if (ce.content)
+ saveToCache(ds, ce.content);
+ }
+
+ if (d->options & MergedResult)
+ saveToCache(ds, mergedContent);
+
+ if (ds.status() != QDataStream::Ok)
+ throw Exception("error writing content");
+ } catch (const Exception &e) {
+ if (warnings)
+ *warnings << qL1S("Failed to write Cache: ") + qL1S(e.what());
+ else
+ qCWarning(LogCache) << "Failed to write Cache:" << e.what();
+ }
+ qCDebug(LogCache) << d->cacheBaseName << "writing the cache finished after"
+ << (timer.nsecsElapsed() / 1000) << "usec";
+ }
+ }
+
+ d->cache = cache;
+ if (d->options & MergedResult)
+ d->mergedContent = mergedContent;
+
+ qCDebug(LogCache) << d->cacheBaseName << "finished cache parsing after"
+ << (timer.nsecsElapsed() / 1000) << "usec";
+}
+
+void AbstractConfigCache::clear()
+{
+ for (auto &ce : qAsConst(d->cache))
+ destruct(ce.content);
+ d->cache.clear();
+ d->cacheIndex.clear();
+ destruct(d->mergedContent);
+ d->mergedContent = nullptr;
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/common-lib/configcache.h b/src/common-lib/configcache.h
new file mode 100644
index 00000000..3c15710a
--- /dev/null
+++ b/src/common-lib/configcache.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <functional>
+
+#include <QPair>
+#include <QVector>
+#include <QStringList>
+#include <QVariant>
+#include <QIODevice>
+#include <QtAppManCommon/global.h>
+
+QT_BEGIN_NAMESPACE_AM
+
+class ConfigCachePrivate;
+
+template <typename T> class ConfigCacheAdaptor
+{
+public:
+ T *loadFromSource(QIODevice *source, const QString &fileName);
+ T *loadFromCache(QDataStream &ds);
+ void saveToCache(QDataStream &ds, const T *t);
+ void merge(T *to, const T *from) { *to = *from; }
+
+ QStringList *warnings;
+};
+
+class AbstractConfigCache
+{
+public:
+ enum Option {
+ None = 0x0,
+ MergedResult = 0x1,
+ NoCache = 0x2,
+ ClearCache = 0x4
+ };
+ Q_DECLARE_FLAGS(Options, Option)
+
+ AbstractConfigCache(const QStringList &configFiles, const QString &cacheBaseName, Options options = None);
+ virtual ~AbstractConfigCache();
+
+ virtual void parse(QStringList *warnings = nullptr);
+
+ void *takeMergedResult() const;
+ void *takeResult(int index) const;
+ void *takeResult(const QString &rawFile) const;
+
+ void clear();
+
+protected:
+ virtual void *loadFromSource(QIODevice *source, const QString &fileName) = 0;
+ virtual void preProcessSourceContent(QByteArray &sourceContent, const QString &fileName) = 0;
+ virtual void *loadFromCache(QDataStream &ds) = 0;
+ virtual void saveToCache(QDataStream &ds, const void *t) = 0;
+ virtual void merge(void *to, const void *from) = 0;
+ virtual void destruct(void *t) = 0;
+
+private:
+ Q_DISABLE_COPY(AbstractConfigCache)
+
+ ConfigCachePrivate *d;
+};
+
+template <typename T, typename ADAPTOR = ConfigCacheAdaptor<T>> class ConfigCache : public AbstractConfigCache
+{
+public:
+ using AbstractConfigCache::Option;
+ using AbstractConfigCache::Options;
+
+ ConfigCache(const QStringList &configFiles, const QString &cacheBaseName, Options options = None)
+ : AbstractConfigCache(configFiles, cacheBaseName, options)
+ { }
+
+ ~ConfigCache()
+ {
+ clear();
+ }
+
+ void parse(QStringList *warnings = nullptr) override
+ {
+ m_adaptor.warnings = warnings;
+ AbstractConfigCache::parse(warnings);
+ }
+
+ T *takeMergedResult() const
+ {
+ return static_cast<T *>(AbstractConfigCache::takeMergedResult());
+ }
+ T *takeResult(int index) const
+ {
+ return static_cast<T *>(AbstractConfigCache::takeResult(index));
+ }
+ T *takeResult(const QString &yamlFile) const
+ {
+ return static_cast<T *>(AbstractConfigCache::takeResult(yamlFile));
+ }
+
+protected:
+ void *loadFromSource(QIODevice *source, const QString &fileName) override
+ { return m_adaptor.loadFromSource(source, fileName); }
+ void preProcessSourceContent(QByteArray &sourceContent, const QString &fileName) override
+ { m_adaptor.preProcessSourceContent(sourceContent, fileName); }
+ void *loadFromCache(QDataStream &ds) override
+ { return m_adaptor.loadFromCache(ds); }
+ void saveToCache(QDataStream &ds, const void *t) override
+ { m_adaptor.saveToCache(ds, static_cast<const T *>(t)); }
+ void merge(void *to, const void *from) override
+ { m_adaptor.merge(static_cast<T *>(to), static_cast<const T *>(from)); }
+ void destruct(void *t) override
+ { delete static_cast<T *>(t); }
+
+ ADAPTOR m_adaptor;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractConfigCache::Options)
+
+QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/applicationdatabase.h b/src/common-lib/configcache_p.h
index 7d11f4a9..8e690097 100644
--- a/src/manager-lib/applicationdatabase.h
+++ b/src/common-lib/configcache_p.h
@@ -1,10 +1,10 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
-** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -42,37 +42,43 @@
#pragma once
-#include <QtAppManCommon/global.h>
-#include <QList>
-#include <QString>
+#include "configcache.h"
QT_BEGIN_NAMESPACE_AM
-class Application;
-class AbstractApplication;
-class ApplicationDatabasePrivate;
-
-class ApplicationDatabase
+struct ConfigCacheEntry
{
-public:
- explicit ApplicationDatabase();
- explicit ApplicationDatabase(const QString &fileName);
- ~ApplicationDatabase();
+ QString filePath; // abs. file path
+ QByteArray checksum; // sha1 (fast and sufficient for this use-case)
+ QByteArray rawContent; // raw YAML content
+ void *content = nullptr; // parsed YAML content
+ bool checksumMatches = false;
+};
- bool isValid() const;
- bool isTemporary() const;
- QString errorString() const;
- QString name() const;
+struct CacheHeader
+{
+ enum { Magic = 0x23d39366, // dd if=/dev/random bs=4 count=1 status=none | xxd -p
+ Version = 1 };
+ static quint64 s_globalId;
- QVector<AbstractApplication *> read() Q_DECL_NOEXCEPT_EXPR(false);
- void write(const QVector<AbstractApplication *> &apps) Q_DECL_NOEXCEPT_EXPR(false);
- void write(const QVector<AbstractApplicationInfo *> &apps) Q_DECL_NOEXCEPT_EXPR(false);
+ quint32 magic = Magic;
+ quint32 version = Version;
+ quint64 globalId = 0;
+ QString baseName;
+ quint32 entries = 0;
- void invalidate();
+ bool isValid(const QString &baseName) const;
+};
-private:
- ApplicationDatabasePrivate *d;
- Q_DISABLE_COPY(ApplicationDatabase)
+class ConfigCachePrivate
+{
+public:
+ AbstractConfigCache::Options options;
+ QStringList rawFiles;
+ QString cacheBaseName;
+ QVector<ConfigCacheEntry> cache;
+ QMap<QString, int> cacheIndex;
+ void *mergedContent = nullptr;
};
QT_END_NAMESPACE_AM
diff --git a/src/common-lib/crashhandler.cpp b/src/common-lib/crashhandler.cpp
index 480dca9a..fd196dff 100644
--- a/src/common-lib/crashhandler.cpp
+++ b/src/common-lib/crashhandler.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/crashhandler.h b/src/common-lib/crashhandler.h
index 79b42730..b09104a8 100644
--- a/src/common-lib/crashhandler.h
+++ b/src/common-lib/crashhandler.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/dbus-utilities.cpp b/src/common-lib/dbus-utilities.cpp
index ff74fb7f..1a8267b6 100644
--- a/src/common-lib/dbus-utilities.cpp
+++ b/src/common-lib/dbus-utilities.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/dbus-utilities.h b/src/common-lib/dbus-utilities.h
index c135d142..fa3de40c 100644
--- a/src/common-lib/dbus-utilities.h
+++ b/src/common-lib/dbus-utilities.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/error.h b/src/common-lib/error.h
index 1e1c16c8..6204783d 100644
--- a/src/common-lib/error.h
+++ b/src/common-lib/error.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/exception.cpp b/src/common-lib/exception.cpp
index 11a54d89..ba3e8020 100644
--- a/src/common-lib/exception.cpp
+++ b/src/common-lib/exception.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/exception.h b/src/common-lib/exception.h
index 3dcdc03a..6a238bb3 100644
--- a/src/common-lib/exception.h
+++ b/src/common-lib/exception.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -89,6 +90,27 @@ public:
return *this;
}
+ // this will generate compiler errors if there's no suitable QString::arg(const C &) overload
+ template <typename C> typename QtPrivate::QEnableIf<QtPrivate::IsSequentialContainer<C>::Value, Exception>::Type &
+ arg(const C &c) Q_DECL_NOEXCEPT
+ {
+ QString s;
+ for (int i = 0; i < c.size(); ++i) {
+ s += qSL("%1").arg(c.at(i));
+ if (i < (c.size() - 1))
+ s.append(qL1S(", "));
+ }
+ m_errorString = m_errorString.arg(s);
+ return *this;
+ }
+
+ // QStringList is always special
+ Exception &arg(const QStringList &sl) Q_DECL_NOEXCEPT
+ {
+ return arg(static_cast<QList<QString>>(sl));
+ }
+
+ // this will generate compiler errors if there's no suitable QString::arg(const Ts &) overload
template <typename... Ts> Exception &arg(const Ts & ...ts) Q_DECL_NOEXCEPT
{
m_errorString = m_errorString.arg(ts...);
diff --git a/src/common-lib/global.h b/src/common-lib/global.h
index c1172b7b..72cec409 100644
--- a/src/common-lib/global.h
+++ b/src/common-lib/global.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/logging.cpp b/src/common-lib/logging.cpp
index 064610b5..74d9a7c6 100644
--- a/src/common-lib/logging.cpp
+++ b/src/common-lib/logging.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -73,8 +74,8 @@ Q_CORE_EXPORT void qWinMsgHandler(QtMsgType t, const char* str);
QT_BEGIN_NAMESPACE_AM
#if defined(QT_GENIVIEXTRAS_LIB)
-static const char *s_defaultSystemUiDltId = "LXAM";
-static const char *s_defaultSystemUiDltDescription = "Luxoft Application-Manager";
+static const char *s_defaultSystemUiDltId = "QTAM";
+static const char *s_defaultSystemUiDltDescription = "Qt Application Manager";
#endif
/*
@@ -105,6 +106,10 @@ static const char *s_defaultSystemUiDltDescription = "Luxoft Application-Manager
\li \c QML
\li General QML related messages
\row
+ \li \c am.runtime
+ \li \c RT
+ \li Runtime messages
+\row
\li \c am.runtime.qml
\li \c QMRT
\li QML runtime messages
@@ -125,6 +130,10 @@ static const char *s_defaultSystemUiDltDescription = "Luxoft Application-Manager
\li \c INTN
\li Intent sub-system messages
\row
+ \li \c am.cache
+ \li \c CACH
+ \li Cache sub-system messages
+\row
\li \c general
\li \c GEN
\li Used for DLT logging only and enabled by default. Categories that have no context ID
@@ -139,11 +148,13 @@ QDLT_LOGGING_CATEGORY(LogInstaller, "am.installer", "INST", "Installer sub-syste
QDLT_LOGGING_CATEGORY(LogGraphics, "am.graphics", "GRPH", "OpenGL/UI related messages")
QDLT_LOGGING_CATEGORY(LogWaylandDebug, "am.wayland.debug", "WAYL", "Wayland related messages")
QDLT_LOGGING_CATEGORY(LogQml, "am.qml", "QML", "General QML related messages")
+QDLT_LOGGING_CATEGORY(LogRuntime, "am.runtime", "RT", "Runtime messages")
QDLT_LOGGING_CATEGORY(LogQmlRuntime, "am.runtime.qml", "QMRT", "QML runtime messages")
QDLT_LOGGING_CATEGORY(LogQmlIpc, "am.qml.ipc", "QMIP", "QML IPC messages")
QDLT_LOGGING_CATEGORY(LogNotifications, "am.notify", "NTFY", "Notifications sub-system messages")
QDLT_LOGGING_CATEGORY(LogDeployment, "am.deployment", "DPLM", "Deployment hints")
QDLT_LOGGING_CATEGORY(LogIntents, "am.intent", "INTN", "Intents sub-system messages")
+QDLT_LOGGING_CATEGORY(LogCache, "am.cache", "CACH", "Cache sub-system messages")
QDLT_LOGGING_CATEGORY(LogGeneral, "general", "GEN", "Messages without dedicated context ID (fallback)")
QDLT_FALLBACK_CATEGORY(LogGeneral)
@@ -391,10 +402,10 @@ QVariant Logging::useAMConsoleLogger()
void Logging::useAMConsoleLogger(const QVariant &config)
{
s_useAMConsoleLoggerConfig = config;
- if (!s_useAMConsoleLoggerConfig.isValid())
- s_useAMConsoleLogger = !s_messagePatternDefined;
- else
+ if (s_useAMConsoleLoggerConfig.userType() == QMetaType::Bool)
s_useAMConsoleLogger = s_useAMConsoleLoggerConfig.toBool();
+ else
+ s_useAMConsoleLogger = !s_messagePatternDefined;
}
QByteArray Logging::applicationId()
diff --git a/src/common-lib/logging.h b/src/common-lib/logging.h
index 7671a6cb..054d8cdb 100644
--- a/src/common-lib/logging.h
+++ b/src/common-lib/logging.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -53,10 +54,12 @@ Q_DECLARE_LOGGING_CATEGORY(LogGraphics)
Q_DECLARE_LOGGING_CATEGORY(LogWaylandDebug)
Q_DECLARE_LOGGING_CATEGORY(LogQml)
Q_DECLARE_LOGGING_CATEGORY(LogNotifications)
+Q_DECLARE_LOGGING_CATEGORY(LogRuntime)
Q_DECLARE_LOGGING_CATEGORY(LogQmlRuntime)
Q_DECLARE_LOGGING_CATEGORY(LogQmlIpc)
Q_DECLARE_LOGGING_CATEGORY(LogDeployment)
Q_DECLARE_LOGGING_CATEGORY(LogIntents)
+Q_DECLARE_LOGGING_CATEGORY(LogCache)
class Logging
{
diff --git a/src/common-lib/processtitle.cpp b/src/common-lib/processtitle.cpp
index c65cdb8f..e2b9401e 100644
--- a/src/common-lib/processtitle.cpp
+++ b/src/common-lib/processtitle.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/processtitle.h b/src/common-lib/processtitle.h
index cecbc150..90c83af5 100644
--- a/src/common-lib/processtitle.h
+++ b/src/common-lib/processtitle.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/qml-utilities.cpp b/src/common-lib/qml-utilities.cpp
index 7cf29393..f3d43965 100644
--- a/src/common-lib/qml-utilities.cpp
+++ b/src/common-lib/qml-utilities.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/qml-utilities.h b/src/common-lib/qml-utilities.h
index 9c9f125d..e13a1f10 100644
--- a/src/common-lib/qml-utilities.h
+++ b/src/common-lib/qml-utilities.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/qtyaml.cpp b/src/common-lib/qtyaml.cpp
index fbb75f50..f6a625ac 100644
--- a/src/common-lib/qtyaml.cpp
+++ b/src/common-lib/qtyaml.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -41,257 +42,23 @@
****************************************************************************/
#include <QVariant>
-#include <QRegExp>
+#include <QRegularExpression>
#include <QDebug>
#include <QtNumeric>
+#include <QTextCodec>
+#include <QFileInfo>
+#include <QDir>
#include <yaml.h>
#include "global.h"
#include "qtyaml.h"
+#include "exception.h"
-QT_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE_AM
-namespace QtYaml {
-
-static QVariant convertYamlNodeToVariant(yaml_document_t *doc, yaml_node_t *node)
-{
- QVariant result;
-
- if (!doc)
- return result;
- if (!node)
- return result;
-
- switch (node->type) {
- case YAML_SCALAR_NODE: {
- const QByteArray ba = QByteArray::fromRawData(reinterpret_cast<const char *>(node->data.scalar.value),
- int(node->data.scalar.length));
-
- if (node->data.scalar.style == YAML_SINGLE_QUOTED_SCALAR_STYLE
- || node->data.scalar.style == YAML_DOUBLE_QUOTED_SCALAR_STYLE) {
- result = QString::fromUtf8(ba);
- break;
- }
-
- enum ValueIndex {
- ValueNull,
- ValueTrue,
- ValueFalse,
- ValueNaN,
- ValueInf
- };
-
- struct StaticMapping
- {
- const char *text;
- ValueIndex index;
- };
-
- static QVariant staticValues[] = {
- QVariant(), // ValueNull
- QVariant(true), // ValueTrue
- QVariant(false), // ValueFalse
- QVariant(qQNaN()), // ValueNaN
- QVariant(qInf()), // ValueInf
- };
-
- static const StaticMapping staticMappings[] = { // keep this sorted for bsearch !!
- { "", ValueNull },
- { ".INF", ValueInf },
- { ".Inf", ValueInf },
- { ".NAN", ValueNaN },
- { ".NaN", ValueNaN },
- { ".inf", ValueInf },
- { ".nan", ValueNaN },
- { "FALSE", ValueFalse },
- { "False", ValueFalse },
- { "N", ValueFalse },
- { "NO", ValueFalse },
- { "NULL", ValueNull },
- { "No", ValueFalse },
- { "Null", ValueNull },
- { "OFF", ValueFalse },
- { "Off", ValueFalse },
- { "ON", ValueTrue },
- { "On", ValueTrue },
- { "TRUE", ValueTrue },
- { "True", ValueTrue },
- { "Y", ValueTrue },
- { "YES", ValueTrue },
- { "Yes", ValueTrue },
- { "false", ValueFalse },
- { "n", ValueFalse },
- { "no", ValueFalse },
- { "null", ValueNull },
- { "off", ValueFalse },
- { "on", ValueTrue },
- { "true", ValueTrue },
- { "y", ValueTrue },
- { "yes", ValueTrue },
- { "~", ValueNull }
- };
-
- static const char *firstCharStaticMappings = ".FNOTYfnoty~";
- char firstChar = ba.isEmpty() ? 0 : ba.at(0);
-
- if (strchr(firstCharStaticMappings, firstChar)) { // cheap check to avoid expensive bsearch
- StaticMapping key { ba.constData(), ValueNull };
- auto found = bsearch(&key,
- staticMappings,
- sizeof(staticMappings)/sizeof(staticMappings[0]),
- sizeof(staticMappings[0]),
- [](const void *m1, const void *m2) {
- return strcmp(static_cast<const StaticMapping *>(m1)->text,
- static_cast<const StaticMapping *>(m2)->text); });
-
- if (found) {
- result = staticValues[static_cast<StaticMapping *>(found)->index];
- break;
- }
- }
-
- QString str = QString::fromUtf8(ba);
- result = str;
-
- if ((firstChar >= '0' && firstChar <= '9') // cheap check to avoid expensive regexps
- || firstChar == '+' || firstChar == '-' || firstChar == '.') {
- static const QRegExp numberRegExps[] = {
- QRegExp(qSL("[-+]?0b[0-1_]+")), // binary
- QRegExp(qSL("[-+]?0x[0-9a-fA-F_]+")), // hexadecimal
- QRegExp(qSL("[-+]?0[0-7_]+")), // octal
- QRegExp(qSL("[-+]?(0|[1-9][0-9_]*)")), // decimal
- QRegExp(qSL("[-+]?([0-9][0-9_]*)?\\.[0-9.]*([eE][-+][0-9]+)?")), // float
- QRegExp()
- };
-
- for (int numberIndex = 0; !numberRegExps[numberIndex].isEmpty(); ++numberIndex) {
- if (numberRegExps[numberIndex].exactMatch(str)) {
- bool ok = false;
- QVariant val;
-
- // YAML allows _ as a grouping separator
- if (str.contains(qL1C('_')))
- str = str.replace(qL1C('_'), qSL(""));
-
- if (numberIndex == 4) {
- val = str.toDouble(&ok);
- } else {
- int base = 10;
-
- switch (numberIndex) {
- case 0: base = 2; str.replace(qSL("0b"), qSL("")); break; // Qt chokes on 0b
- case 1: base = 16; break;
- case 2: base = 8; break;
- case 3: base = 10; break;
- }
-
- qint64 s64 = str.toLongLong(&ok, base);
- if (ok && (s64 <= std::numeric_limits<qint32>::max())) {
- val = qint32(s64);
- } else if (ok) {
- val = s64;
- } else {
- quint64 u64 = str.toULongLong(&ok, base);
-
- if (ok && (u64 <= std::numeric_limits<quint32>::max()))
- val = quint32(u64);
- else if (ok)
- val = u64;
- }
- }
- if (ok) {
- result = val;
- break;
- }
- }
- }
- }
- break;
- }
- case YAML_SEQUENCE_NODE: {
- QVariantList array;
- for (auto seq = node->data.sequence.items.start; seq < node->data.sequence.items.top; ++seq) {
- yaml_node_t *seqNode = yaml_document_get_node(doc, *seq);
- if (seqNode)
- array.append(convertYamlNodeToVariant(doc, seqNode));
- else
- array.append(QVariant());
- }
- result = array;
- break;
- }
- case YAML_MAPPING_NODE: {
- QVariantMap object;
- for (auto map = node->data.mapping.pairs.start; map < node->data.mapping.pairs.top; ++map) {
- yaml_node_t *keyNode = yaml_document_get_node(doc, map->key);
- yaml_node_t *valueNode = yaml_document_get_node(doc, map->value);
- if (keyNode && valueNode) {
- QVariant key = convertYamlNodeToVariant(doc, keyNode);
- QString keyStr = key.toString();
-
- if (key.type() != QVariant::String)
- qWarning() << "YAML Parser: converting non-string mapping key to string for JSON compatibility";
- if (object.contains(keyStr))
- qWarning() << "YAML Parser: duplicate key" << keyStr << "found in mapping";
-
- object.insert(keyStr, convertYamlNodeToVariant(doc, valueNode));
- }
- }
- result = object;
- break;
- }
- default:
- break;
- }
-
- return result;
-}
-
-
-QVector<QVariant> variantDocumentsFromYaml(const QByteArray &yaml, ParseError *error)
-{
- QVector<QVariant> result;
-
- if (error)
- *error = ParseError();
-
- yaml_parser_t p;
- if (yaml_parser_initialize(&p)) {
- yaml_parser_set_input_string(&p, reinterpret_cast<const uchar *>(yaml.constData()),
- static_cast<size_t>(yaml.size()));
-
- yaml_document_t doc;
- yaml_node_t *root;
- do {
- if (!yaml_parser_load(&p, &doc)) {
- if (error) {
- switch (p.error) {
- case YAML_READER_ERROR:
- *error = ParseError(QString::fromLocal8Bit(p.problem), -1, -1, int(p.problem_offset));
- break;
- case YAML_SCANNER_ERROR:
- case YAML_PARSER_ERROR:
- *error = ParseError(QString::fromLocal8Bit(p.problem), int(p.problem_mark.line + 1), int(p.problem_mark.column), int(p.problem_mark.index));
- break;
- default:
- break;
- }
- }
- }
- root = yaml_document_get_root_node(&doc);
- if (root)
- result.append(convertYamlNodeToVariant(&doc, root));
- yaml_document_delete(&doc);
- } while (root);
-
- yaml_parser_delete(&p);
- } else if (error) {
- *error = ParseError(qSL("could not initialize YAML parser"));
- }
- return result;
-}
+namespace QtYaml {
static inline void yerr(int result) Q_DECL_NOEXCEPT_EXPR(false)
{
@@ -412,6 +179,499 @@ QByteArray yamlFromVariantDocuments(const QVector<QVariant> &documents, YamlStyl
return out;
}
+
} // namespace QtYaml
-QT_END_NAMESPACE
+
+class YamlParserPrivate
+{
+public:
+ QString sourceName;
+ QString sourceDir;
+ QByteArray data;
+ QTextCodec *codec = nullptr;
+ bool parsedHeader = false;
+ yaml_parser_t parser;
+ yaml_event_t event;
+
+};
+
+
+YamlParser::YamlParser(const QByteArray &data, const QString &fileName)
+ : d(new YamlParserPrivate)
+{
+ d->data = data;
+ if (!fileName.isEmpty()) {
+ QFileInfo fi(fileName);
+ d->sourceDir = fi.absolutePath();
+ d->sourceName = fi.fileName();
+ }
+
+ memset(&d->parser, 0, sizeof(d->parser));
+ memset(&d->event, 0, sizeof(d->event));
+
+ if (!yaml_parser_initialize(&d->parser))
+ throw Exception("Failed to initialize YAML parser");
+ yaml_parser_set_input_string(&d->parser, reinterpret_cast<const unsigned char *>(d->data.constData()),
+ static_cast<size_t>(d->data.size()));
+ nextEvent();
+ if (d->event.type != YAML_STREAM_START_EVENT)
+ throw Exception("Invalid YAML data");
+ switch (d->event.data.stream_start.encoding) {
+ default:
+ case YAML_UTF8_ENCODING: d->codec = QTextCodec::codecForName("UTF-8"); break;
+ case YAML_UTF16LE_ENCODING: d->codec = QTextCodec::codecForName("UTF-16LE"); break;
+ case YAML_UTF16BE_ENCODING: d->codec = QTextCodec::codecForName("UTF-16BE"); break;
+ }
+}
+
+YamlParser::~YamlParser()
+{
+ if (d->event.type != YAML_NO_EVENT)
+ yaml_event_delete(&d->event);
+ yaml_parser_delete(&d->parser);
+ delete d;
+}
+
+QString YamlParser::sourcePath() const
+{
+ return QDir(sourceDir()).absoluteFilePath(sourceName());
+}
+
+QString YamlParser::sourceDir() const
+{
+ return d->sourceDir;
+}
+
+QString YamlParser::sourceName() const
+{
+ return d->sourceName;
+}
+
+QVector<QVariant> YamlParser::parseAllDocuments(const QByteArray &yaml)
+{
+ YamlParser p(yaml);
+ QVector<QVariant> result;
+ while (p.nextDocument())
+ result << p.parseMap();
+ return result;
+}
+
+QPair<QString, int> YamlParser::parseHeader()
+{
+ if (d->parsedHeader)
+ throw Exception("Already parsed header");
+ if (d->event.type != YAML_STREAM_START_EVENT)
+ throw Exception("Header must be the first document of a file");
+ if (!nextDocument())
+ throw Exception("No header document available");
+ if (!isMap())
+ throw Exception("Header document is not a map");
+
+ QPair<QString, int> result;
+
+ Fields fields = {
+ { "formatType", true, YamlParser::Scalar, [&result](YamlParser *parser) {
+ result.first = parser->parseScalar().toString(); } },
+ { "formatVersion", true, YamlParser::Scalar, [&result](YamlParser *parser) {
+ result.second = parser->parseScalar().toInt(); } }
+ };
+
+ parseFields(fields);
+
+ d->parsedHeader = true;
+ return result;
+}
+
+bool YamlParser::nextDocument()
+{
+ while (d->event.type != YAML_STREAM_END_EVENT) {
+ nextEvent();
+ if (d->event.type == YAML_DOCUMENT_START_EVENT) {
+ nextEvent(); // advance to the first child or end-of-document
+ return true;
+ }
+ }
+ return false;
+}
+
+void YamlParser::nextEvent()
+{
+ if (d->event.type != YAML_NO_EVENT)
+ yaml_event_delete(&d->event);
+
+ do {
+ if (!yaml_parser_parse(&d->parser, &d->event))
+ throw YamlParserException(this, "invalid YAML syntax");
+ if (d->event.type == YAML_ALIAS_EVENT)
+ throw YamlParserException(this, "anchors and aliases are not supported");
+ } while (d->event.type == YAML_NO_EVENT);
+}
+
+bool YamlParser::isScalar() const
+{
+ return d->event.type == YAML_SCALAR_EVENT;
+}
+
+QString YamlParser::parseString() const
+{
+ if (!isScalar())
+ return QString{};
+
+ Q_ASSERT(d->event.data.scalar.value);
+ Q_ASSERT(static_cast<int>(d->event.data.scalar.length) >= 0);
+
+ return QTextDecoder(d->codec).toUnicode(reinterpret_cast<const char *>(d->event.data.scalar.value),
+ static_cast<int>(d->event.data.scalar.length));
+}
+
+QVariant YamlParser::parseScalar() const
+{
+ QString scalar = parseString();
+
+ if (scalar.isEmpty()
+ || d->event.data.scalar.style == YAML_SINGLE_QUOTED_SCALAR_STYLE
+ || d->event.data.scalar.style == YAML_DOUBLE_QUOTED_SCALAR_STYLE) {
+ return scalar;
+ }
+
+ enum ValueIndex {
+ ValueNull,
+ ValueTrue,
+ ValueFalse,
+ ValueNaN,
+ ValueInf
+ };
+
+ struct StaticMapping
+ {
+ QString text;
+ ValueIndex index;
+ };
+
+ static const QVariant staticValues[] = {
+ QVariant::fromValue(nullptr), // ValueNull
+ QVariant(true), // ValueTrue
+ QVariant(false), // ValueFalse
+ QVariant(qQNaN()), // ValueNaN
+ QVariant(qInf()), // ValueInf
+ };
+
+ static const StaticMapping staticMappings[] = { // keep this sorted for bsearch !!
+ { qSL(""), ValueNull },
+ { qSL(".INF"), ValueInf },
+ { qSL(".Inf"), ValueInf },
+ { qSL(".NAN"), ValueNaN },
+ { qSL(".NaN"), ValueNaN },
+ { qSL(".inf"), ValueInf },
+ { qSL(".nan"), ValueNaN },
+ { qSL("FALSE"), ValueFalse },
+ { qSL("False"), ValueFalse },
+ { qSL("N"), ValueFalse },
+ { qSL("NO"), ValueFalse },
+ { qSL("NULL"), ValueNull },
+ { qSL("No"), ValueFalse },
+ { qSL("Null"), ValueNull },
+ { qSL("OFF"), ValueFalse },
+ { qSL("Off"), ValueFalse },
+ { qSL("ON"), ValueTrue },
+ { qSL("On"), ValueTrue },
+ { qSL("TRUE"), ValueTrue },
+ { qSL("True"), ValueTrue },
+ { qSL("Y"), ValueTrue },
+ { qSL("YES"), ValueTrue },
+ { qSL("Yes"), ValueTrue },
+ { qSL("false"), ValueFalse },
+ { qSL("n"), ValueFalse },
+ { qSL("no"), ValueFalse },
+ { qSL("null"), ValueNull },
+ { qSL("off"), ValueFalse },
+ { qSL("on"), ValueTrue },
+ { qSL("true"), ValueTrue },
+ { qSL("y"), ValueTrue },
+ { qSL("yes"), ValueTrue },
+ { qSL("~"), ValueNull }
+ };
+
+ static const char *firstCharStaticMappings = ".FNOTYfnoty~";
+ char firstChar = scalar.isEmpty() ? 0 : scalar.at(0).toLatin1();
+
+ if (strchr(firstCharStaticMappings, firstChar)) { // cheap check to avoid expensive bsearch
+ StaticMapping key { scalar, ValueNull };
+ auto found = bsearch(&key,
+ staticMappings,
+ sizeof(staticMappings) / sizeof(staticMappings[0]),
+ sizeof(staticMappings[0]),
+ [](const void *m1, const void *m2) {
+ return static_cast<const StaticMapping *>(m1)->text.compare(static_cast<const StaticMapping *>(m2)->text);
+ });
+
+ if (found)
+ return staticValues[static_cast<StaticMapping *>(found)->index];
+ }
+
+ if ((firstChar >= '0' && firstChar <= '9') // cheap check to avoid expensive regexps
+ || firstChar == '+' || firstChar == '-' || firstChar == '.') {
+ static const QRegularExpression numberRegExps[] = {
+ QRegularExpression(qSL("\\A[-+]?(0|[1-9][0-9_]*)\\z")), // decimal
+ QRegularExpression(qSL("\\A[-+]?([0-9][0-9_]*)?\\.[0-9.]*([eE][-+][0-9]+)?\\z")), // float
+ QRegularExpression(qSL("\\A[-+]?0x[0-9a-fA-F_]+\\z")), // hexadecimal
+ QRegularExpression(qSL("\\A[-+]?0b[0-1_]+\\z")), // binary
+ QRegularExpression(qSL("\\A[-+]?0[0-7_]+\\z")), // octal
+ };
+ for (size_t numberIndex = 0; numberIndex < (sizeof(numberRegExps) / sizeof(*numberRegExps)); ++numberIndex) {
+ if (numberRegExps[numberIndex].match(scalar).hasMatch()) {
+ bool ok = false;
+ QVariant val;
+
+ // YAML allows _ as a grouping separator
+ if (scalar.contains(qL1C('_')))
+ scalar = scalar.replace(qL1C('_'), qSL(""));
+
+ if (numberIndex == 1) {
+ val = scalar.toDouble(&ok);
+ } else {
+ int base = 10;
+
+ switch (numberIndex) {
+ case 0: base = 10; break;
+ case 2: base = 16; break;
+ case 3: base = 2; scalar.replace(qSL("0b"), qSL("")); break; // Qt chokes on 0b
+ case 4: base = 8; break;
+ }
+
+ qint64 s64 = scalar.toLongLong(&ok, base);
+ if (ok && (s64 <= std::numeric_limits<qint32>::max())) {
+ val = qint32(s64);
+ } else if (ok) {
+ val = s64;
+ } else {
+ quint64 u64 = scalar.toULongLong(&ok, base);
+
+ if (ok && (u64 <= std::numeric_limits<quint32>::max()))
+ val = quint32(u64);
+ else if (ok)
+ val = u64;
+ }
+ }
+ if (ok)
+ return val;
+ }
+ }
+ }
+ return scalar;
+}
+
+bool YamlParser::isMap() const
+{
+ return d->event.type == YAML_MAPPING_START_EVENT;
+}
+
+QString YamlParser::parseMapKey()
+{
+ if (isScalar()) {
+ QVariant key = parseScalar();
+ if (key.type() == QVariant::String)
+ return key.toString();
+ }
+ throw YamlParserException(this, "Only strings are supported as mapping keys");
+}
+
+QVariantMap YamlParser::parseMap()
+{
+ if (!isMap())
+ return QVariantMap {};
+
+ QVariantMap map;
+ while (true) {
+ nextEvent(); // read key
+ if (d->event.type == YAML_MAPPING_END_EVENT)
+ return map;
+
+ QString key = parseMapKey();
+ if (map.contains(key))
+ throw YamlParserException(this, "Found duplicate key '%1' in mapping").arg(key);
+
+ nextEvent(); // read value
+ QVariant value = parseVariant();
+
+ map.insert(key, value);
+ }
+}
+
+bool YamlParser::isList() const
+{
+ return d->event.type == YAML_SEQUENCE_START_EVENT;
+}
+
+void YamlParser::parseList(const std::function<void(YamlParser *p)> &callback)
+{
+ if (!isList())
+ throw YamlParserException(this, "Cannot parse non-list as list");
+
+ while (true) {
+ nextEvent(); // read next value
+
+ if (d->event.type == YAML_SEQUENCE_END_EVENT)
+ return;
+
+ switch (d->event.type) {
+ case YAML_SCALAR_EVENT:
+ case YAML_MAPPING_START_EVENT:
+ case YAML_SEQUENCE_START_EVENT:
+ callback(this);
+ break;
+ default:
+ throw YamlParserException(this, "Unexpected event (%1) encountered while parsing a list").arg(d->event.type);
+ }
+ }
+}
+
+QVariant YamlParser::parseVariant()
+{
+ QVariant value;
+ if (isScalar()) {
+ value = parseScalar();
+ } else if (isList()) {
+ value = parseList();
+ } else if (isMap()) {
+ value = parseMap();
+ } else {
+ throw YamlParserException(this, "Unexpected event (%1) encountered while parsing a variant")
+ .arg(d->event.type);
+ }
+ return value;
+}
+
+QVariantList YamlParser::parseList()
+{
+ QVariantList list;
+ parseList([&list](YamlParser *p) {
+ list.append(p->parseVariant());
+ });
+ return list;
+}
+
+QStringList YamlParser::parseStringOrStringList()
+{
+ if (isList()) {
+ QStringList result;
+ parseList([&result](YamlParser *p) {
+ if (!p->isScalar())
+ throw YamlParserException(p, "A list or map is not a valid member of a string-list");
+ result.append(p->parseString());
+ });
+ return result;
+ } else if (isScalar()) {
+ return { parseString() };
+ } else {
+ throw YamlParserException(this, "Cannot parse a map as string or string-list");
+ }
+}
+
+void YamlParser::parseFields(const std::vector<Field> &fields)
+{
+ if (!isMap())
+ throw YamlParserException(this, "Expected a map (type %1) to parse fields from, but got type %2")
+ .arg(YAML_MAPPING_START_EVENT).arg(d->event.type);
+
+ QVector<QString> fieldsFound;
+
+ while (true) {
+ nextEvent(); // read key
+ if (d->event.type == YAML_MAPPING_END_EVENT)
+ break;
+ QString key = parseMapKey();
+ if (fieldsFound.contains(key))
+ throw YamlParserException(this, "Found duplicate key '%1' in mapping").arg(key);
+
+ auto field = fields.cbegin();
+ for (; field != fields.cend(); ++field) {
+ if (key == qL1S(field->name))
+ break;
+ }
+ if (field == fields.cend())
+ throw YamlParserException(this, "Field '%1' is not valid in this context").arg(key);
+ fieldsFound << key;
+
+ nextEvent(); // read value
+ QVector<yaml_event_type_t> allowedEvents;
+ if (field->types & YamlParser::Scalar)
+ allowedEvents.append(YAML_SCALAR_EVENT);
+ if (field->types & YamlParser::Map)
+ allowedEvents.append(YAML_MAPPING_START_EVENT);
+ if (field->types & YamlParser::List)
+ allowedEvents.append(YAML_SEQUENCE_START_EVENT);
+
+ if (!allowedEvents.contains(d->event.type)) { // ALIASES MISSING HERE!
+ auto mapEventNames = [](const QVector<yaml_event_type_t> &events) -> QString {
+ static const QHash<yaml_event_type_t, const char *> eventNames = {
+ { YAML_NO_EVENT, "nothing" },
+ { YAML_STREAM_START_EVENT, "stream start" },
+ { YAML_STREAM_END_EVENT, "stream end" },
+ { YAML_DOCUMENT_START_EVENT, "document start" },
+ { YAML_DOCUMENT_END_EVENT, "document end" },
+ { YAML_ALIAS_EVENT, "alias" },
+ { YAML_SCALAR_EVENT, "scalar" },
+ { YAML_SEQUENCE_START_EVENT, "sequence start" },
+ { YAML_SEQUENCE_END_EVENT, "sequence end" },
+ { YAML_MAPPING_START_EVENT, "mapping start" },
+ { YAML_MAPPING_END_EVENT, "mapping end" }
+ };
+ QString names;
+ for (int i = 0; i < events.size(); ++i) {
+ if (i)
+ names.append(i == (events.size() - 1) ? qL1S(" or ") : qL1S(", "));
+ names.append(qL1S(eventNames.value(events.at(i), "<unknown>")));
+ }
+ return names;
+ };
+
+ throw YamlParserException(this, "Field '%1' expected to be of type '%2', but got '%3'")
+ .arg(field->name).arg(mapEventNames(allowedEvents)).arg(mapEventNames({ d->event.type }));
+ }
+
+ yaml_event_type_t typeBefore = d->event.type;
+ yaml_event_type_t typeAfter;
+ switch (typeBefore) {
+ case YAML_MAPPING_START_EVENT: typeAfter = YAML_MAPPING_END_EVENT; break;
+ case YAML_SEQUENCE_START_EVENT: typeAfter = YAML_SEQUENCE_END_EVENT; break;
+ default: typeAfter = typeBefore; break;
+ }
+ field->callback(this);
+ if (d->event.type != typeAfter) {
+ throw YamlParserException(this, "Invalid YAML event state after field callback for '%3': expected %1, but got %2")
+ .arg(typeAfter).arg(d->event.type).arg(key);
+ }
+ }
+ QStringList fieldsMissing;
+ for (auto field : fields) {
+ if (field.required && !fieldsFound.contains(qL1S(field.name)))
+ fieldsMissing.append(qL1S(field.name));
+ }
+ if (!fieldsMissing.isEmpty())
+ throw YamlParserException(this, "Required fields are missing: %1").arg(fieldsMissing);
+}
+
+YamlParserException::YamlParserException(YamlParser *p, const char *errorString)
+ : Exception(Error::Parse, "YAML parse error")
+{
+ bool isProblem = p->d->parser.problem;
+ yaml_mark_t &mark = isProblem ? p->d->parser.problem_mark : p->d->parser.mark;
+
+ QString context = QTextDecoder(p->d->codec).toUnicode(p->d->data);
+ int lpos = context.lastIndexOf(qL1C('\n'), int(mark.index ? mark.index - 1 : 0));
+ int rpos = context.indexOf(qL1C('\n'), int(mark.index));
+ context = context.mid(lpos + 1, rpos == -1 ? context.size() : rpos - lpos - 1);
+ int contextPos = int(mark.index) - (lpos + 1);
+
+ m_errorString.append(qSL(":\nfile://%1:%2:%3: error").arg(p->sourcePath()).arg(mark.line + 1).arg(mark.column + 1));
+ if (errorString)
+ m_errorString.append(qSL(": %1").arg(qL1S(errorString)));
+ if (isProblem)
+ m_errorString.append(qSL(": %1").arg(QString::fromUtf8(p->d->parser.problem)));
+ if (!context.isEmpty())
+ m_errorString.append(qSL("\n %1\n %2^").arg(context, QString(contextPos, qL1C(' '))));
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/common-lib/qtyaml.h b/src/common-lib/qtyaml.h
index 11edb200..33d51ec9 100644
--- a/src/common-lib/qtyaml.h
+++ b/src/common-lib/qtyaml.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -43,14 +44,17 @@
#pragma once
#include <functional>
+#include <vector>
#include <QJsonParseError>
#include <QVector>
#include <QByteArray>
#include <QString>
#include <QVariant>
+#include <QtAppManCommon/global.h>
+#include <QtAppManCommon/exception.h>
-QT_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE_AM
namespace QtYaml {
@@ -89,4 +93,78 @@ QByteArray yamlFromVariantDocuments(const QVector<QVariant> &maps, YamlStyle sty
} // namespace QtYaml
-QT_END_NAMESPACE
+class YamlParserPrivate;
+class YamlParserException;
+
+class YamlParser
+{
+public:
+ YamlParser(const QByteArray &data, const QString &fileName = QString());
+ ~YamlParser();
+
+ QString sourcePath() const;
+ QString sourceDir() const;
+ QString sourceName() const;
+
+ static QVector<QVariant> parseAllDocuments(const QByteArray &yaml);
+
+ QPair<QString, int> parseHeader();
+
+ bool nextDocument();
+ void nextEvent();
+
+ bool isScalar() const;
+ QVariant parseScalar() const;
+ QString parseString() const;
+
+ bool isMap() const;
+ QVariantMap parseMap();
+
+ bool isList() const;
+ QVariantList parseList();
+ void parseList(const std::function<void (YamlParser *)> &callback);
+
+ // convenience
+ QVariant parseVariant();
+ QStringList parseStringOrStringList();
+
+ enum FieldType { Scalar = 0x01, List = 0x02, Map = 0x04 };
+ Q_DECLARE_FLAGS(FieldTypes, FieldType)
+ struct Field
+ {
+ QByteArray name;
+ bool required;
+ FieldTypes types;
+ std::function<void(YamlParser *)> callback;
+
+ Field(const char *_name, bool _required, FieldTypes _types,
+ const std::function<void(YamlParser *)> &_callback)
+ : name(_name)
+ , required(_required)
+ , types(_types)
+ , callback(_callback)
+ { }
+ };
+ typedef std::vector<Field> Fields;
+
+ void parseFields(const Fields &fields);
+
+private:
+ Q_DISABLE_COPY(YamlParser)
+
+ QString parseMapKey();
+
+ YamlParserPrivate *d;
+ friend class YamlParserException;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(YamlParser::FieldTypes)
+
+class YamlParserException : public Exception
+{
+public:
+ explicit YamlParserException(YamlParser *p, const char *errorString);
+};
+
+QT_END_NAMESPACE_AM
+// We mean it. Dummy comment since syncqt needs this also for completely private Qt modules.
diff --git a/src/common-lib/startuptimer.cpp b/src/common-lib/startuptimer.cpp
index 861df663..5e143093 100644
--- a/src/common-lib/startuptimer.cpp
+++ b/src/common-lib/startuptimer.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -329,14 +329,15 @@ StartupTimer::StartupTimer()
size_t procInfoSize;
if (sysctl(mibNames, sizeof(mibNames) / sizeof(mibNames[0]), nullptr, &procInfoSize, nullptr, 0) == 0) {
- kinfo_proc *procInfo = (kinfo_proc *) malloc(procInfoSize);
+ kinfo_proc *procInfo = static_cast<kinfo_proc *>(malloc(procInfoSize));
if (sysctl(mibNames, sizeof(mibNames) / sizeof(mibNames[0]), procInfo, &procInfoSize, nullptr, 0) == 0) {
struct timeval now;
if (gettimeofday(&now, nullptr) == 0) {
- m_processCreation = (quint64(now.tv_sec) * 1000000 + now.tv_usec)
- - (procInfo->kp_proc.p_un.__p_starttime.tv_sec * 1000000 + procInfo->kp_proc.p_un.__p_starttime.tv_usec);
+ m_processCreation = (quint64(now.tv_sec) * 1000000 + quint64(now.tv_usec))
+ - (quint64(procInfo->kp_proc.p_un.__p_starttime.tv_sec) * 1000000
+ + quint64(procInfo->kp_proc.p_un.__p_starttime.tv_usec));
m_initialized = true;
}
} else {
@@ -353,7 +354,7 @@ StartupTimer::StartupTimer()
size_t bootTimeLen = sizeof(bootTime);
int mibNames[2] = { CTL_KERN, KERN_BOOTTIME };
if (sysctl(mibNames, sizeof(mibNames) / sizeof(mibNames[0]), &bootTime, &bootTimeLen, nullptr, 0) == 0 ) {
- m_systemUpTime = (time(nullptr) - bootTime.tv_sec) * 1000; // we don't need more precision on macOS
+ m_systemUpTime = quint64(time(nullptr) - bootTime.tv_sec) * 1000; // we don't need more precision on macOS
emit systemUpTimeChanged(m_systemUpTime);
}
}
@@ -450,10 +451,9 @@ void StartupTimer::createReport(const QString &title)
if (m_output == stderr)
getOutputInformation(&ansiColorSupport, nullptr, nullptr);
- const char *format = "\n== STARTUP TIMING REPORT: %s ==\n";
- if (ansiColorSupport)
- format = "\n\033[33m== STARTUP TIMING REPORT: %s ==\033[0m\n";
- fprintf(m_output, format, title.toLocal8Bit().data());
+ constexpr const char *plainFormat = "\n== STARTUP TIMING REPORT: %s ==\n";
+ constexpr const char *colorFormat = "\n\033[33m== STARTUP TIMING REPORT: %s ==\033[0m\n";
+ fprintf(m_output, ansiColorSupport ? colorFormat : plainFormat, title.toLocal8Bit().data());
static const int barCols = 60;
@@ -475,12 +475,11 @@ void StartupTimer::createReport(const QString &title)
QByteArray spacing(maxTextLen - text.length(), ' ');
SplitSeconds ss = splitMicroSecs(usec);
- const char *format = "%d'%03d.%03d %s %s#%s\n";
- if (ansiColorSupport)
- format = "\033[32m%d'%03d.%03d\033[0m %s %s\033[44m %s\033[0m\n";
+ constexpr const char *plainFormat = "%d'%03d.%03d %s %s#%s\n";
+ constexpr const char *colorFormat = "\033[32m%d'%03d.%03d\033[0m %s %s\033[44m %s\033[0m\n";
- fprintf(m_output, format, ss.sec, ss.msec, ss.usec,
- text.constData(), spacing.constData(), bar.constData());
+ fprintf(m_output, ansiColorSupport ? colorFormat : plainFormat,
+ ss.sec, ss.msec, ss.usec, text.constData(), spacing.constData(), bar.constData());
}
fflush(m_output);
diff --git a/src/common-lib/startuptimer.h b/src/common-lib/startuptimer.h
index ab2ead55..89f9282e 100644
--- a/src/common-lib/startuptimer.h
+++ b/src/common-lib/startuptimer.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/unixsignalhandler.cpp b/src/common-lib/unixsignalhandler.cpp
index 897a3103..cd51fae3 100644
--- a/src/common-lib/unixsignalhandler.cpp
+++ b/src/common-lib/unixsignalhandler.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/unixsignalhandler.h b/src/common-lib/unixsignalhandler.h
index da2fd0d5..f1de44f1 100644
--- a/src/common-lib/unixsignalhandler.h
+++ b/src/common-lib/unixsignalhandler.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/common-lib/utilities.cpp b/src/common-lib/utilities.cpp
index b489fe56..c70d6abb 100644
--- a/src/common-lib/utilities.cpp
+++ b/src/common-lib/utilities.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -104,43 +105,63 @@ QT_BEGIN_NAMESPACE_AM
Check a YAML document against the "standard" AM header.
If \a numberOfDocuments is positive, the number of docs need to match exactly. If it is
negative, the \a numberOfDocuments is taken as the required minimum amount of documents.
-
+ Otherwise, the amount of documents is irrelevant.
*/
-void checkYamlFormat(const QVector<QVariant> &docs, int numberOfDocuments,
- const QVector<QByteArray> &formatTypes, int formatVersion) Q_DECL_NOEXCEPT_EXPR(false)
+YamlFormat checkYamlFormat(const QVector<QVariant> &docs, int numberOfDocuments,
+ const QVector<YamlFormat> &formatTypesAndVersions) Q_DECL_NOEXCEPT_EXPR(false)
{
int actualSize = docs.size();
- QByteArray actualFormatType;
- int actualFormatVersion = 0;
-
- if (actualSize >= 1) {
- const auto map = docs.constFirst().toMap();
- actualFormatType = map.value(qSL("formatType")).toString().toUtf8();
- actualFormatVersion = map.value(qSL("formatVersion")).toInt();
- }
+ if (actualSize < 1)
+ throw Exception("no header YAML document found");
if (numberOfDocuments < 0) {
- if (actualSize < numberOfDocuments) {
+ if (actualSize < -numberOfDocuments) {
throw Exception("wrong number of YAML documents: expected at least %1, got %2")
.arg(-numberOfDocuments).arg(actualSize);
}
- } else {
+ } else if (numberOfDocuments > 0) {
if (actualSize != numberOfDocuments) {
throw Exception("wrong number of YAML documents: expected %1, got %2")
.arg(numberOfDocuments).arg(actualSize);
}
}
- if (!formatTypes.contains(actualFormatType)) {
- throw Exception("wrong formatType header: expected %1, got %2")
- .arg(QString::fromUtf8(formatTypes.toList().join(", or ")), QString::fromUtf8(actualFormatType));
- }
- if (actualFormatVersion != formatVersion) {
- throw Exception("wrong formatVersion header: expected %1, got %2")
- .arg(formatVersion).arg(actualFormatVersion);
+
+ const auto map = docs.constFirst().toMap();
+ YamlFormat actualFormatTypeAndVersion = {
+ map.value(qSL("formatType")).toString(),
+ map.value(qSL("formatVersion")).toInt()
+ };
+
+ class StringifyTypeAndVersion
+ {
+ public:
+ StringifyTypeAndVersion() = default;
+ StringifyTypeAndVersion(const QPair<QString, int> &typeAndVersion)
+ {
+ operator()(typeAndVersion);
+ }
+ QString string() const
+ {
+ return m_str;
+ }
+ void operator()(const QPair<QString, int> &typeAndVersion)
+ {
+ if (!m_str.isEmpty())
+ m_str += qSL(", or ");
+ m_str = m_str + typeAndVersion.first + qSL(" version ") + QString::number(typeAndVersion.second);
+ }
+ private:
+ QString m_str;
+ };
+
+ if (!formatTypesAndVersions.contains(actualFormatTypeAndVersion)) {
+ throw Exception("wrong header: expected %1, got %2")
+ .arg(std::for_each(formatTypesAndVersions.cbegin(), formatTypesAndVersions.cend(), StringifyTypeAndVersion()).string())
+ .arg(StringifyTypeAndVersion(actualFormatTypeAndVersion).string());
}
+ return actualFormatTypeAndVersion;
}
-
QMultiMap<QString, QString> mountedDirectories()
{
QMultiMap<QString, QString> result;
diff --git a/src/common-lib/utilities.h b/src/common-lib/utilities.h
index 9910ce1c..dd07913c 100644
--- a/src/common-lib/utilities.h
+++ b/src/common-lib/utilities.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -43,9 +44,15 @@
#pragma once
#include <QVector>
+#include <QPair>
#include <QByteArray>
#include <QMultiMap>
#include <QVariant>
+#include <QString>
+#include <QUrl>
+#include <QDir>
+#include <QResource>
+#include <QLibrary>
#include <QtAppManCommon/global.h>
@@ -57,8 +64,10 @@ QT_BEGIN_NAMESPACE_AM
int timeoutFactor();
-void checkYamlFormat(const QVector<QVariant> &docs, int numberOfDocuments,
- const QVector<QByteArray> &formatTypes, int formatVersion) Q_DECL_NOEXCEPT_EXPR(false);
+using YamlFormat = QPair<QString, int>;
+
+YamlFormat checkYamlFormat(const QVector<QVariant> &docs, int numberOfDocuments,
+ const QVector<YamlFormat> &formatTypesAndVersions) Q_DECL_NOEXCEPT_EXPR(false);
/*! \internal
Convenience function that makes it easy to accept a plain string where
@@ -70,6 +79,28 @@ inline QStringList variantToStringList(const QVariant &v)
: v.toStringList();
}
+// Translate between QFile and QUrl (resource) representations.
+// For some weird reason, QFile cannot cope with "qrc:" and QUrl cannot cope with ":".
+inline QUrl filePathToUrl(const QString &path, const QString &baseDir)
+{
+ return path.startsWith(qSL(":")) ? QUrl(qSL("qrc") + path)
+ : QUrl::fromUserInput(path, baseDir, QUrl::AssumeLocalFile);
+}
+
+inline QString urlToLocalFilePath(const QUrl &url)
+{
+ if (url.isLocalFile())
+ return url.toLocalFile();
+ else if (url.scheme() == qSL("qrc"))
+ return qL1C(':') + url.path();
+ return QString();
+}
+
+inline QString toAbsoluteFilePath(const QString &path, const QString &baseDir = QDir::currentPath())
+{
+ return path.startsWith(qSL("qrc:")) ? path.mid(3) : QDir(baseDir).absoluteFilePath(path);
+}
+
/*! \internal
Recursively merge the second QVariantMap into the first one
*/
@@ -120,4 +151,12 @@ QVector<T *> loadPlugins(const char *type, const QStringList &files) Q_DECL_NOEX
return result;
}
+// Load a Qt resource, either in the form of a resource file or a plugin
+inline bool loadResource(const QString &resource)
+{
+ return QLibrary::isLibrary(resource)
+ ? (QLibrary(QDir().absoluteFilePath(resource)).load() || QResource::registerResource(resource))
+ : (QResource::registerResource(resource) || QLibrary(QDir().absoluteFilePath(resource)).load());
+}
+
QT_END_NAMESPACE_AM
diff --git a/src/crypto-lib/cryptography.cpp b/src/crypto-lib/cryptography.cpp
index 17feaaa5..6e3fb327 100644
--- a/src/crypto-lib/cryptography.cpp
+++ b/src/crypto-lib/cryptography.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/crypto-lib/cryptography.h b/src/crypto-lib/cryptography.h
index e5b609b9..bc3c8a28 100644
--- a/src/crypto-lib/cryptography.h
+++ b/src/crypto-lib/cryptography.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/crypto-lib/libcryptofunction.cpp b/src/crypto-lib/libcryptofunction.cpp
index 943f9df0..362307cd 100644
--- a/src/crypto-lib/libcryptofunction.cpp
+++ b/src/crypto-lib/libcryptofunction.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/crypto-lib/libcryptofunction.h b/src/crypto-lib/libcryptofunction.h
index 5e8ff057..d60537d5 100644
--- a/src/crypto-lib/libcryptofunction.h
+++ b/src/crypto-lib/libcryptofunction.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/crypto-lib/signature.cpp b/src/crypto-lib/signature.cpp
index 34b33e29..320f17b0 100644
--- a/src/crypto-lib/signature.cpp
+++ b/src/crypto-lib/signature.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/crypto-lib/signature.h b/src/crypto-lib/signature.h
index 3b4dbd87..2e26d81c 100644
--- a/src/crypto-lib/signature.h
+++ b/src/crypto-lib/signature.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/crypto-lib/signature_macos.cpp b/src/crypto-lib/signature_macos.cpp
index fd565cd2..824474fc 100644
--- a/src/crypto-lib/signature_macos.cpp
+++ b/src/crypto-lib/signature_macos.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/crypto-lib/signature_openssl.cpp b/src/crypto-lib/signature_openssl.cpp
index 7fa38d54..27b999a9 100644
--- a/src/crypto-lib/signature_openssl.cpp
+++ b/src/crypto-lib/signature_openssl.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/crypto-lib/signature_p.h b/src/crypto-lib/signature_p.h
index e16896dc..1a8bee96 100644
--- a/src/crypto-lib/signature_p.h
+++ b/src/crypto-lib/signature_p.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/crypto-lib/signature_win.cpp b/src/crypto-lib/signature_win.cpp
index 1e05c013..31cc5fc3 100644
--- a/src/crypto-lib/signature_win.cpp
+++ b/src/crypto-lib/signature_win.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/dbus-lib/abstractdbuscontextadaptor.cpp b/src/dbus-lib/abstractdbuscontextadaptor.cpp
index 0716b3e4..aee9a521 100644
--- a/src/dbus-lib/abstractdbuscontextadaptor.cpp
+++ b/src/dbus-lib/abstractdbuscontextadaptor.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/dbus-lib/abstractdbuscontextadaptor.h b/src/dbus-lib/abstractdbuscontextadaptor.h
index 683dc04f..4753e636 100644
--- a/src/dbus-lib/abstractdbuscontextadaptor.h
+++ b/src/dbus-lib/abstractdbuscontextadaptor.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/dbus-lib/applicationinstallerdbuscontextadaptor.cpp b/src/dbus-lib/applicationinstallerdbuscontextadaptor.cpp
deleted file mode 100644
index de5097cd..00000000
--- a/src/dbus-lib/applicationinstallerdbuscontextadaptor.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Luxoft Sweden AB
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Luxoft Application Manager.
-**
-** $QT_BEGIN_LICENSE:LGPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** 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-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: LGPL-3.0
-**
-****************************************************************************/
-
-#include "applicationinstallerdbuscontextadaptor.h"
-#include "applicationinstaller.h"
-#include "io.qt.applicationinstaller_adaptor.h"
-#include "dbuspolicy.h"
-#include "exception.h"
-#include "logging.h"
-
-
-QT_BEGIN_NAMESPACE_AM
-
-static QString taskStateToString(AsynchronousTask::TaskState state)
-{
- const char *cstr = QMetaEnum::fromType<AsynchronousTask::TaskState>().valueToKey(state);
- return QString::fromUtf8(cstr);
-}
-
-ApplicationInstallerDBusContextAdaptor::ApplicationInstallerDBusContextAdaptor(ApplicationInstaller *ai)
- : AbstractDBusContextAdaptor(ai)
-{
- m_adaptor = new ApplicationInstallerAdaptor(this);
-}
-
-QT_END_NAMESPACE_AM
-
-/////////////////////////////////////////////////////////////////////////////////////
-
-QT_USE_NAMESPACE_AM
-
-ApplicationInstallerAdaptor::ApplicationInstallerAdaptor(QObject *parent)
- : QDBusAbstractAdaptor(parent)
-{
- auto ai = ApplicationInstaller::instance();
-
- connect(ai, &ApplicationInstaller::taskBlockingUntilInstallationAcknowledge,
- this, &ApplicationInstallerAdaptor::taskBlockingUntilInstallationAcknowledge);
- connect(ai, &ApplicationInstaller::taskFailed,
- this, &ApplicationInstallerAdaptor::taskFailed);
- connect(ai, &ApplicationInstaller::taskFinished,
- this, &ApplicationInstallerAdaptor::taskFinished);
- connect(ai, &ApplicationInstaller::taskProgressChanged,
- this, &ApplicationInstallerAdaptor::taskProgressChanged);
- connect(ai, &ApplicationInstaller::taskRequestingInstallationAcknowledge,
- this, &ApplicationInstallerAdaptor::taskRequestingInstallationAcknowledge);
- connect(ai, &ApplicationInstaller::taskStarted,
- this, &ApplicationInstallerAdaptor::taskStarted);
- connect(ai, &ApplicationInstaller::taskStateChanged,
- [this](const QString &taskId, AsynchronousTask::TaskState newState) {
- emit taskStateChanged(taskId, taskStateToString(newState));
- });
-}
-
-ApplicationInstallerAdaptor::~ApplicationInstallerAdaptor()
-{ }
-
-bool ApplicationInstallerAdaptor::allowInstallationOfUnsignedPackages() const
-{
- return ApplicationInstaller::instance()->allowInstallationOfUnsignedPackages();
-}
-
-bool ApplicationInstallerAdaptor::applicationUserIdSeparation() const
-{
- return ApplicationInstaller::instance()->isApplicationUserIdSeparationEnabled();
-}
-
-uint ApplicationInstallerAdaptor::commonApplicationGroupId() const
-{
- return ApplicationInstaller::instance()->commonApplicationGroupId();
-}
-
-bool ApplicationInstallerAdaptor::developmentMode() const
-{
- return ApplicationInstaller::instance()->developmentMode();
-}
-
-void ApplicationInstallerAdaptor::acknowledgePackageInstallation(const QString &taskId)
-{
- AM_AUTHENTICATE_DBUS(void)
- return ApplicationInstaller::instance()->acknowledgePackageInstallation(taskId);
-}
-
-bool ApplicationInstallerAdaptor::cancelTask(const QString &taskId)
-{
- AM_AUTHENTICATE_DBUS(bool)
- return ApplicationInstaller::instance()->cancelTask(taskId);
-}
-
-int ApplicationInstallerAdaptor::compareVersions(const QString &version1, const QString &version2)
-{
- AM_AUTHENTICATE_DBUS(int)
- return ApplicationInstaller::instance()->compareVersions(version1, version2);
-}
-
-QVariantMap ApplicationInstallerAdaptor::getInstallationLocation(const QString &installationLocationId)
-{
- AM_AUTHENTICATE_DBUS(QVariantMap)
- return ApplicationInstaller::instance()->getInstallationLocation(installationLocationId);
-}
-
-QString ApplicationInstallerAdaptor::installationLocationIdFromApplication(const QString &id)
-{
- AM_AUTHENTICATE_DBUS(QString)
- return ApplicationInstaller::instance()->installationLocationIdFromApplication(id);
-}
-
-QStringList ApplicationInstallerAdaptor::installationLocationIds()
-{
- AM_AUTHENTICATE_DBUS(QStringList)
- return ApplicationInstaller::instance()->installationLocationIds();
-}
-
-qlonglong ApplicationInstallerAdaptor::installedApplicationSize(const QString &id)
-{
- AM_AUTHENTICATE_DBUS(qlonglong)
- return ApplicationInstaller::instance()->installedApplicationSize(id);
-}
-
-QVariantMap ApplicationInstallerAdaptor::installedApplicationExtraMetaData(const QString &id)
-{
- AM_AUTHENTICATE_DBUS(QVariantMap)
- return ApplicationInstaller::instance()->installedApplicationExtraMetaData(id);
-}
-
-QVariantMap ApplicationInstallerAdaptor::installedApplicationExtraSignedMetaData(const QString &id)
-{
- AM_AUTHENTICATE_DBUS(QVariantMap)
- return ApplicationInstaller::instance()->installedApplicationExtraSignedMetaData(id);
-}
-
-QString ApplicationInstallerAdaptor::removePackage(const QString &id, bool keepDocuments)
-{
- return removePackage(id, keepDocuments, false);
-}
-
-QString ApplicationInstallerAdaptor::removePackage(const QString &id, bool keepDocuments, bool force)
-{
- AM_AUTHENTICATE_DBUS(QString)
- return ApplicationInstaller::instance()->removePackage(id, keepDocuments, force);
-}
-
-QString ApplicationInstallerAdaptor::startPackageInstallation(const QString &installationLocationId, const QString &sourceUrl)
-{
- AM_AUTHENTICATE_DBUS(QString)
- return ApplicationInstaller::instance()->startPackageInstallation(installationLocationId, sourceUrl);
-}
-
-QString ApplicationInstallerAdaptor::taskState(const QString &taskId)
-{
- AM_AUTHENTICATE_DBUS(QString)
- return taskStateToString(ApplicationInstaller::instance()->taskState(taskId));
-}
-
-QString ApplicationInstallerAdaptor::taskApplicationId(const QString &taskId)
-{
- AM_AUTHENTICATE_DBUS(QString)
- return ApplicationInstaller::instance()->taskApplicationId(taskId);
-}
-
-QStringList ApplicationInstallerAdaptor::activeTaskIds()
-{
- AM_AUTHENTICATE_DBUS(QStringList)
- return ApplicationInstaller::instance()->activeTaskIds();
-}
diff --git a/src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp b/src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp
index 3ca02d65..5794e79a 100644
--- a/src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp
+++ b/src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/dbus-lib/applicationmanagerdbuscontextadaptor.h b/src/dbus-lib/applicationmanagerdbuscontextadaptor.h
index 073697cd..02a2a805 100644
--- a/src/dbus-lib/applicationmanagerdbuscontextadaptor.h
+++ b/src/dbus-lib/applicationmanagerdbuscontextadaptor.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/dbus-lib/dbus-lib.pro b/src/dbus-lib/dbus-lib.pro
index 567fb0f3..5635fdf0 100644
--- a/src/dbus-lib/dbus-lib.pro
+++ b/src/dbus-lib/dbus-lib.pro
@@ -32,10 +32,9 @@ ADAPTORS_XML = \
org.freedesktop.notifications.xml \
!disable-installer {
- QT *= appman_installer-private
- HEADERS += applicationinstallerdbuscontextadaptor.h
- SOURCES += applicationinstallerdbuscontextadaptor.cpp
- ADAPTORS_XML += io.qt.applicationinstaller.xml
+ HEADERS += packagemanagerdbuscontextadaptor.h
+ SOURCES += packagemanagerdbuscontextadaptor.cpp
+ ADAPTORS_XML += io.qt.packagemanager.xml
}
!headless{
@@ -46,7 +45,7 @@ ADAPTORS_XML = \
}
OTHER_FILES = \
- io.qt.applicationinstaller.xml \
+ io.qt.packagemanager.xml \
io.qt.applicationmanager.applicationinterface.xml \
io.qt.applicationmanager.runtimeinterface.xml \
io.qt.applicationmanager.intentinterface.xml \
@@ -59,8 +58,8 @@ qtPrepareTool(QDBUSCPP2XML, qdbuscpp2xml)
recreate-applicationmanager-dbus-xml.CONFIG = phony
recreate-applicationmanager-dbus-xml.commands = $$QDBUSCPP2XML -a $$PWD/../manager-lib/applicationmanager.h -o $$PWD/io.qt.applicationmanager.xml
-recreate-applicationinstaller-dbus-xml.CONFIG = phony
-recreate-applicationinstaller-dbus-xml.commands = $$QDBUSCPP2XML -a $$PWD/../installer-lib/applicationinstaller.h -o $$PWD/io.qt.applicationinstaller.xml
+recreate-packagemanager-dbus-xml.CONFIG = phony
+recreate-packagemanager-dbus-xml.commands = $$QDBUSCPP2XML -a $$PWD/../installer-lib/packagemanager.h -o $$PWD/io.qt.packagemanager.xml
recreate-windowmanager-dbus-xml.CONFIG = phony
recreate-windowmanager-dbus-xml.commands = $$QDBUSCPP2XML -a $$PWD/../manager/windowmanager.h -o $$PWD/io.qt.windowmanager.xml
@@ -70,7 +69,7 @@ recreate-dbus-xml.depends = recreate-applicationmanager-dbus-xml recreate-applic
QMAKE_EXTRA_TARGETS += \
recreate-dbus-xml \
recreate-applicationmanager-dbus-xml \
- recreate-applicationinstaller-dbus-xml \
+ recreate-packagemanager-dbus-xml \
recreate-windowmanager-dbus-xml \
load(qt_module)
diff --git a/src/dbus-lib/dbusdaemon.cpp b/src/dbus-lib/dbusdaemon.cpp
index 94533c3e..0e0117f7 100644
--- a/src/dbus-lib/dbusdaemon.cpp
+++ b/src/dbus-lib/dbusdaemon.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/dbus-lib/dbusdaemon.h b/src/dbus-lib/dbusdaemon.h
index 34569bc3..ca3fdd4b 100644
--- a/src/dbus-lib/dbusdaemon.h
+++ b/src/dbus-lib/dbusdaemon.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/dbus-lib/dbuspolicy.cpp b/src/dbus-lib/dbuspolicy.cpp
index bf1a66b5..ef6214f6 100644
--- a/src/dbus-lib/dbuspolicy.cpp
+++ b/src/dbus-lib/dbuspolicy.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/dbus-lib/dbuspolicy.h b/src/dbus-lib/dbuspolicy.h
index fcdeed9c..e32c03d4 100644
--- a/src/dbus-lib/dbuspolicy.h
+++ b/src/dbus-lib/dbuspolicy.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/dbus-lib/io.qt.applicationinstaller.xml b/src/dbus-lib/io.qt.packagemanager.xml
index 913ce760..37e41b9d 100644
--- a/src/dbus-lib/io.qt.applicationinstaller.xml
+++ b/src/dbus-lib/io.qt.packagemanager.xml
@@ -1,10 +1,16 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
- <interface name="io.qt.ApplicationInstaller">
+ <interface name="io.qt.PackageManager">
<property name="allowInstallationOfUnsignedPackages" type="b" access="read"/>
<property name="developmentMode" type="b" access="read"/>
<property name="applicationUserIdSeparation" type="b" access="read"/>
<property name="commonApplicationGroupId" type="u" access="read"/>
+ <property name="installationLocation" type="v" access="read">
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap"/>
+ </property>
+ <property name="documentLocation" type="v" access="read">
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap"/>
+ </property>
<signal name="taskStarted">
<arg name="taskId" type="s" direction="out"/>
</signal>
@@ -26,7 +32,7 @@
</signal>
<signal name="taskRequestingInstallationAcknowledge">
<arg name="taskId" type="s" direction="out"/>
- <arg name="applicationAsVariantMap" type="a{sv}" direction="out"/>
+ <arg name="packageAsVariantMap" type="a{sv}" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
<arg name="packageExtraMetaData" type="a{sv}" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out2" value="QVariantMap"/>
@@ -36,21 +42,16 @@
<signal name="taskBlockingUntilInstallationAcknowledge">
<arg name="taskId" type="s" direction="out"/>
</signal>
- <method name="installationLocationIds">
+ <method name="packageIds">
<arg type="as" direction="out"/>
</method>
- <method name="installationLocationIdFromApplication">
- <arg type="s" direction="out"/>
- <arg name="id" type="s" direction="in"/>
- </method>
- <method name="getInstallationLocation">
+ <method name="get">
<arg type="a{sv}" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
- <arg name="installationLocationId" type="s" direction="in"/>
+ <arg name="id" type="s" direction="in"/>
</method>
<method name="startPackageInstallation">
<arg type="s" direction="out"/>
- <arg name="installationLocationId" type="s" direction="in"/>
<arg name="sourceUrl" type="s" direction="in"/>
</method>
<method name="acknowledgePackageInstallation">
@@ -71,7 +72,7 @@
<arg type="s" direction="out"/>
<arg name="taskId" type="s" direction="in"/>
</method>
- <method name="taskApplicationId">
+ <method name="taskPackageId">
<arg type="s" direction="out"/>
<arg name="taskId" type="s" direction="in"/>
</method>
@@ -87,16 +88,16 @@
<arg name="version1" type="s" direction="in"/>
<arg name="version2" type="s" direction="in"/>
</method>
- <method name="installedApplicationSize">
+ <method name="installedPackageSize">
<arg type="x" direction="out"/>
<arg name="id" type="s" direction="in"/>
</method>
- <method name="installedApplicationExtraMetaData">
+ <method name="installedPackageExtraMetaData">
<arg type="a{sv}" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
<arg name="id" type="s" direction="in"/>
</method>
- <method name="installedApplicationExtraSignedMetaData">
+ <method name="installedPackageExtraSignedMetaData">
<arg type="a{sv}" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
<arg name="id" type="s" direction="in"/>
diff --git a/src/dbus-lib/notificationmanagerdbuscontextadaptor.cpp b/src/dbus-lib/notificationmanagerdbuscontextadaptor.cpp
index eeaefaff..ed80d6a5 100644
--- a/src/dbus-lib/notificationmanagerdbuscontextadaptor.cpp
+++ b/src/dbus-lib/notificationmanagerdbuscontextadaptor.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/dbus-lib/notificationmanagerdbuscontextadaptor.h b/src/dbus-lib/notificationmanagerdbuscontextadaptor.h
index bcced38f..6f71bdbe 100644
--- a/src/dbus-lib/notificationmanagerdbuscontextadaptor.h
+++ b/src/dbus-lib/notificationmanagerdbuscontextadaptor.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/dbus-lib/packagemanagerdbuscontextadaptor.cpp b/src/dbus-lib/packagemanagerdbuscontextadaptor.cpp
new file mode 100644
index 00000000..b423389c
--- /dev/null
+++ b/src/dbus-lib/packagemanagerdbuscontextadaptor.cpp
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "packagemanagerdbuscontextadaptor.h"
+#include "packagemanager.h"
+#include "io.qt.packagemanager_adaptor.h"
+#include "dbuspolicy.h"
+#include "exception.h"
+#include "logging.h"
+
+
+QT_BEGIN_NAMESPACE_AM
+
+static QString taskStateToString(AsynchronousTask::TaskState state)
+{
+ const char *cstr = QMetaEnum::fromType<AsynchronousTask::TaskState>().valueToKey(state);
+ return QString::fromUtf8(cstr);
+}
+
+PackageManagerDBusContextAdaptor::PackageManagerDBusContextAdaptor(PackageManager *pm)
+ : AbstractDBusContextAdaptor(pm)
+{
+ m_adaptor = new PackageManagerAdaptor(this);
+}
+
+QT_END_NAMESPACE_AM
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+QT_USE_NAMESPACE_AM
+
+PackageManagerAdaptor::PackageManagerAdaptor(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+{
+ auto ai = PackageManager::instance();
+
+ connect(ai, &PackageManager::taskBlockingUntilInstallationAcknowledge,
+ this, &PackageManagerAdaptor::taskBlockingUntilInstallationAcknowledge);
+ connect(ai, &PackageManager::taskFailed,
+ this, &PackageManagerAdaptor::taskFailed);
+ connect(ai, &PackageManager::taskFinished,
+ this, &PackageManagerAdaptor::taskFinished);
+ connect(ai, &PackageManager::taskProgressChanged,
+ this, &PackageManagerAdaptor::taskProgressChanged);
+ connect(ai, &PackageManager::taskRequestingInstallationAcknowledge,
+ this, &PackageManagerAdaptor::taskRequestingInstallationAcknowledge);
+ connect(ai, &PackageManager::taskStarted,
+ this, &PackageManagerAdaptor::taskStarted);
+ connect(ai, &PackageManager::taskStateChanged,
+ [this](const QString &taskId, AsynchronousTask::TaskState newState) {
+ emit taskStateChanged(taskId, taskStateToString(newState));
+ });
+}
+
+PackageManagerAdaptor::~PackageManagerAdaptor()
+{ }
+
+bool PackageManagerAdaptor::allowInstallationOfUnsignedPackages() const
+{
+ return PackageManager::instance()->allowInstallationOfUnsignedPackages();
+}
+
+bool PackageManagerAdaptor::applicationUserIdSeparation() const
+{
+ return PackageManager::instance()->isApplicationUserIdSeparationEnabled();
+}
+
+uint PackageManagerAdaptor::commonApplicationGroupId() const
+{
+ return PackageManager::instance()->commonApplicationGroupId();
+}
+
+bool PackageManagerAdaptor::developmentMode() const
+{
+ return PackageManager::instance()->developmentMode();
+}
+
+QDBusVariant PackageManagerAdaptor::installationLocation() const
+{
+ return QDBusVariant(PackageManager::instance()->installationLocation());
+}
+
+QDBusVariant PackageManagerAdaptor::documentLocation() const
+{
+ return QDBusVariant(PackageManager::instance()->documentLocation());
+}
+
+void PackageManagerAdaptor::acknowledgePackageInstallation(const QString &taskId)
+{
+ AM_AUTHENTICATE_DBUS(void)
+ return PackageManager::instance()->acknowledgePackageInstallation(taskId);
+}
+
+bool PackageManagerAdaptor::cancelTask(const QString &taskId)
+{
+ AM_AUTHENTICATE_DBUS(bool)
+ return PackageManager::instance()->cancelTask(taskId);
+}
+
+int PackageManagerAdaptor::compareVersions(const QString &version1, const QString &version2)
+{
+ AM_AUTHENTICATE_DBUS(int)
+ return PackageManager::instance()->compareVersions(version1, version2);
+}
+
+QStringList PackageManagerAdaptor::packageIds()
+{
+ AM_AUTHENTICATE_DBUS(QStringList)
+ return PackageManager::instance()->packageIds();
+}
+
+QVariantMap PackageManagerAdaptor::get(const QString &id)
+{
+ AM_AUTHENTICATE_DBUS(QVariantMap)
+ auto map = PackageManager::instance()->get(id);
+ map.remove(qSL("package")); // cannot marshall QObject *
+ return map;
+}
+
+qlonglong PackageManagerAdaptor::installedPackageSize(const QString &packageId)
+{
+ AM_AUTHENTICATE_DBUS(qlonglong)
+ return PackageManager::instance()->installedPackageSize(packageId);
+}
+
+QVariantMap PackageManagerAdaptor::installedPackageExtraMetaData(const QString &packageId)
+{
+ AM_AUTHENTICATE_DBUS(QVariantMap)
+ return PackageManager::instance()->installedPackageExtraMetaData(packageId);
+}
+
+QVariantMap PackageManagerAdaptor::installedPackageExtraSignedMetaData(const QString &packageId)
+{
+ AM_AUTHENTICATE_DBUS(QVariantMap)
+ return PackageManager::instance()->installedPackageExtraSignedMetaData(packageId);
+}
+
+QString PackageManagerAdaptor::removePackage(const QString &packageId, bool keepDocuments)
+{
+ return removePackage(packageId, keepDocuments, false);
+}
+
+QString PackageManagerAdaptor::removePackage(const QString &packageId, bool keepDocuments, bool force)
+{
+ AM_AUTHENTICATE_DBUS(QString)
+ return PackageManager::instance()->removePackage(packageId, keepDocuments, force);
+}
+
+QString PackageManagerAdaptor::startPackageInstallation(const QString &sourceUrl)
+{
+ AM_AUTHENTICATE_DBUS(QString)
+ return PackageManager::instance()->startPackageInstallation(sourceUrl);
+}
+
+QString PackageManagerAdaptor::taskState(const QString &taskId)
+{
+ AM_AUTHENTICATE_DBUS(QString)
+ return taskStateToString(PackageManager::instance()->taskState(taskId));
+}
+
+QString PackageManagerAdaptor::taskPackageId(const QString &taskId)
+{
+ AM_AUTHENTICATE_DBUS(QString)
+ return PackageManager::instance()->taskPackageId(taskId);
+}
+
+QStringList PackageManagerAdaptor::activeTaskIds()
+{
+ AM_AUTHENTICATE_DBUS(QStringList)
+ return PackageManager::instance()->activeTaskIds();
+}
diff --git a/src/dbus-lib/applicationinstallerdbuscontextadaptor.h b/src/dbus-lib/packagemanagerdbuscontextadaptor.h
index 98cac67d..8eb30e88 100644
--- a/src/dbus-lib/applicationinstallerdbuscontextadaptor.h
+++ b/src/dbus-lib/packagemanagerdbuscontextadaptor.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -46,12 +46,12 @@
QT_BEGIN_NAMESPACE_AM
-class ApplicationInstaller;
+class PackageManager;
-class ApplicationInstallerDBusContextAdaptor : public AbstractDBusContextAdaptor
+class PackageManagerDBusContextAdaptor : public AbstractDBusContextAdaptor
{
public:
- explicit ApplicationInstallerDBusContextAdaptor(ApplicationInstaller *am);
+ explicit PackageManagerDBusContextAdaptor(PackageManager *pm);
};
QT_END_NAMESPACE_AM
diff --git a/src/dbus-lib/windowmanagerdbuscontextadaptor.cpp b/src/dbus-lib/windowmanagerdbuscontextadaptor.cpp
index cf18f049..b6b1b5a2 100644
--- a/src/dbus-lib/windowmanagerdbuscontextadaptor.cpp
+++ b/src/dbus-lib/windowmanagerdbuscontextadaptor.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/dbus-lib/windowmanagerdbuscontextadaptor.h b/src/dbus-lib/windowmanagerdbuscontextadaptor.h
index 8d749a3d..a78907bc 100644
--- a/src/dbus-lib/windowmanagerdbuscontextadaptor.h
+++ b/src/dbus-lib/windowmanagerdbuscontextadaptor.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/installer-lib/applicationinstaller.cpp b/src/installer-lib/applicationinstaller.cpp
deleted file mode 100644
index 10fae7ca..00000000
--- a/src/installer-lib/applicationinstaller.cpp
+++ /dev/null
@@ -1,1042 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Luxoft Sweden AB
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Luxoft Application Manager.
-**
-** $QT_BEGIN_LICENSE:LGPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** 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-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: LGPL-3.0
-**
-****************************************************************************/
-
-#include <QCoreApplication>
-#include <QDir>
-#include <QUuid>
-
-#include "logging.h"
-#include "application.h"
-#include "applicationinstaller.h"
-#include "applicationinstaller_p.h"
-#include "installationtask.h"
-#include "deinstallationtask.h"
-#include "sudo.h"
-#include "utilities.h"
-#include "exception.h"
-#include "global.h"
-#include "qml-utilities.h"
-#include "applicationmanager.h"
-
-
-/*!
- \qmltype ApplicationInstaller
- \inqmlmodule QtApplicationManager.SystemUI
- \ingroup system-ui-singletons
- \brief The package installation/removal/update part of the application-manager.
-
- The ApplicationInstaller singleton type handles the package installation
- part of the application manager. It provides both a DBus and QML APIs for
- all of its functionality.
-
- \note The ApplicationInstaller singleton and its corresponding DBus API are only available if you
- specify a base directory for installed application manifests. See \l{Configuration} for details.
-
- \target TaskStates
-
- The following table describes all possible states that a background task could be in:
-
- \table
- \header
- \li Task State
- \li Description
- \row
- \li \c Queued
- \li The task was created and is now queued up for execution.
- \row
- \li \c Executing
- \li The task is being executed.
- \row
- \li \c Finished
- \li The task was executed successfully.
- \row
- \li \c Failed
- \li The task failed to execute successfully.
- \row
- \li \c AwaitingAcknowledge
- \li \e{Installation tasks only!} The task is currently halted, waiting for either
- acknowledgePackageInstallation() or cancelTask() to continue. See startPackageInstallation()
- for more information on the installation workflow.
- \row
- \li \c Installing
- \li \e{Installation tasks only!} The installation was acknowledged via acknowledgePackageInstallation()
- and the final installation phase is now running.
- \row
- \li \c CleaningUp
- \li \e{Installation tasks only!} The installation has finished, and previous installations as
- well as temporary files are being cleaned up.
- \endtable
-
- The normal workflow for tasks is: \c Queued \unicode{0x2192} \c Executing \unicode{0x2192} \c
- Finished. The task can enter the \c Failed state at any point though - either by being canceled via
- cancelTask() or simply by failing due to an error.
-
- Installation tasks are a bit more complex due to the acknowledgment: \c Queued \unicode{0x2192}
- \c Executing \unicode{0x2192} \c AwaitingAcknowledge (this state may be skipped if
- acknowledgePackageInstallation() was called already) \unicode{0x2192} \c Installing
- \unicode{0x2192} \c Cleanup \unicode{0x2192} \c Finished. Again, the task can fail at any point.
-*/
-
-// THIS IS MISSING AN EXAMPLE!
-
-/*!
- \qmlsignal ApplicationInstaller::taskStateChanged(string taskId, string newState)
-
- This signal is emitted when the state of the task identified by \a taskId changes. The
- new state is supplied in the parameter \a newState.
-
- \sa taskState()
-*/
-
-/*!
- \qmlsignal ApplicationInstaller::taskStarted(string taskId)
-
- This signal is emitted when the task identified by \a taskId enters the \c Executing state.
-
- \sa taskStateChanged()
-*/
-
-/*!
- \qmlsignal ApplicationInstaller::taskFinished(string taskId)
-
- This signal is emitted when the task identified by \a taskId enters the \c Finished state.
-
- \sa taskStateChanged()
-*/
-
-/*!
- \qmlsignal ApplicationInstaller::taskFailed(string taskId)
-
- This signal is emitted when the task identified by \a taskId enters the \c Failed state.
-
- \sa taskStateChanged()
-*/
-
-/*!
- \qmlsignal ApplicationInstaller::taskRequestingInstallationAcknowledge(string taskId, object application, object packageExtraMetaData, object packageExtraSignedMetaData)
-
- This signal is emitted when the installation task identified by \a taskId has received enough
- meta-data to be able to emit this signal. The task may be in either \c Executing or \c
- AwaitingAcknowledge state.
-
- The contents of the package's manifest file are supplied via \a application as a JavaScript object.
- Please see the \l {ApplicationManager Roles}{role names} for the expected object fields.
-
- In addition, the package's extra meta-data (signed and unsinged) is also supplied via \a
- packageExtraMetaData and \a packageExtraSignedMetaData respectively as JavaScript objects.
- Both these objects are optional and need to be explicitly either populated during an
- application's packaging step or added by an intermediary app-store server.
- By default, both will just be empty.
-
- Following this signal, either cancelTask() or acknowledgePackageInstallation() has to be called
- for this \a taskId, to either cancel the installation or try to complete it.
-
- The ApplicationInstaller has two convenience functions to help the System-UI with verifying the
- meta-data: compareVersions() and, in case you are using reverse-DNS notation for application-ids,
- validateDnsName().
-
- \sa taskStateChanged(), startPackageInstallation()
-*/
-
-/*!
- \qmlsignal ApplicationInstaller::taskBlockingUntilInstallationAcknowledge(string taskId)
-
- This signal is emitted when the installation task identified by \a taskId cannot continue
- due to a missing acknowledgePackageInstallation() call for the task.
-
- \sa taskStateChanged(), acknowledgePackageInstallation()
-*/
-
-/*!
- \qmlsignal ApplicationInstaller::taskProgressChanged(string taskId, qreal progress)
-
- This signal is emitted whenever the task identified by \a taskId makes progress towards its
- completion. The \a progress is reported as a floating-point number ranging from \c 0.0 to \c 1.0.
-
- \sa taskStateChanged()
-*/
-
-QT_BEGIN_NAMESPACE_AM
-
-ApplicationInstaller *ApplicationInstaller::s_instance = nullptr;
-
-ApplicationInstaller::ApplicationInstaller(const QVector<InstallationLocation> &installationLocations,
- QDir *manifestDir, const QString &hardwareId,
- QObject *parent)
- : QObject(parent)
- , d(new ApplicationInstallerPrivate())
-{
- d->installationLocations = installationLocations;
- d->manifestDir.reset(manifestDir);
- d->hardwareId = hardwareId;
-}
-
-ApplicationInstaller::~ApplicationInstaller()
-{
- delete d;
- s_instance = nullptr;
-}
-
-ApplicationInstaller *ApplicationInstaller::createInstance(const QVector<InstallationLocation> &installationLocations,
- const QString &manifestDirPath,
- const QString &hardwareId, QString *error)
-{
- if (Q_UNLIKELY(s_instance))
- qFatal("ApplicationInstaller::createInstance() was called a second time.");
-
- qRegisterMetaType<AsynchronousTask *>();
- qRegisterMetaType<AsynchronousTask::TaskState>();
-
- QScopedPointer<QDir> manifestDir(new QDir(manifestDirPath));
-
- if (Q_UNLIKELY(!manifestDir->exists())) {
- if (error)
- *error = qL1S("ApplicationInstaller::createInstance() could not access the manifest directory ") + manifestDir->absolutePath();
- return nullptr;
- }
-
- qmlRegisterSingletonType<ApplicationInstaller>("QtApplicationManager.SystemUI", 2, 0, "ApplicationInstaller",
- &ApplicationInstaller::instanceForQml);
-
- return s_instance = new ApplicationInstaller(installationLocations, manifestDir.take(),
- hardwareId, QCoreApplication::instance());
-}
-
-ApplicationInstaller *ApplicationInstaller::instance()
-{
- if (!s_instance)
- qFatal("ApplicationInstaller::instance() was called before createInstance().");
- return s_instance;
-}
-
-QObject *ApplicationInstaller::instanceForQml(QQmlEngine *, QJSEngine *)
-{
- QQmlEngine::setObjectOwnership(instance(), QQmlEngine::CppOwnership);
- return instance();
-}
-
-bool ApplicationInstaller::developmentMode() const
-{
- return d->developmentMode;
-}
-
-void ApplicationInstaller::setDevelopmentMode(bool b)
-{
- d->developmentMode = b;
-}
-
-bool ApplicationInstaller::allowInstallationOfUnsignedPackages() const
-{
- return d->allowInstallationOfUnsignedPackages;
-}
-
-void ApplicationInstaller::setAllowInstallationOfUnsignedPackages(bool b)
-{
- d->allowInstallationOfUnsignedPackages = b;
-}
-
-QString ApplicationInstaller::hardwareId() const
-{
- return d->hardwareId;
-}
-
-bool ApplicationInstaller::isApplicationUserIdSeparationEnabled() const
-{
- return d->userIdSeparation;
-}
-
-uint ApplicationInstaller::commonApplicationGroupId() const
-{
- return d->commonGroupId;
-}
-
-bool ApplicationInstaller::enableApplicationUserIdSeparation(uint minUserId, uint maxUserId, uint commonGroupId)
-{
- if (minUserId >= maxUserId || minUserId == uint(-1) || maxUserId == uint(-1))
- return false;
- d->userIdSeparation = true;
- d->minUserId = minUserId;
- d->maxUserId = maxUserId;
- d->commonGroupId = commonGroupId;
- return true;
-}
-
-uint ApplicationInstaller::findUnusedUserId() const Q_DECL_NOEXCEPT_EXPR(false)
-{
- if (!isApplicationUserIdSeparationEnabled())
- return uint(-1);
-
- QVector<AbstractApplication *> apps = ApplicationManager::instance()->applications();
-
- for (uint uid = d->minUserId; uid <= d->maxUserId; ++uid) {
- bool match = false;
- for (AbstractApplication *app : qAsConst(apps)) {
- if (app->nonAliasedInfo()->uid() == uid) {
- match = true;
- break;
- }
- }
- if (!match)
- return uid;
- }
- throw Exception("could not find a free user-id for application separation in the range %1 to %2")
- .arg(d->minUserId).arg(d->maxUserId);
-}
-
-const QDir *ApplicationInstaller::manifestDirectory() const
-{
- return d->manifestDir.get();
-}
-
-QList<QByteArray> ApplicationInstaller::caCertificates() const
-{
- return d->chainOfTrust;
-}
-
-void ApplicationInstaller::setCACertificates(const QList<QByteArray> &chainOfTrust)
-{
- d->chainOfTrust = chainOfTrust;
-}
-
-void ApplicationInstaller::cleanupBrokenInstallations() const Q_DECL_NOEXCEPT_EXPR(false)
-{
- // Check that everything in the app-db is available
- // -> if not, remove from app-db
-
- ApplicationManager *am = ApplicationManager::instance();
-
- // key: baseDirPath, value: subDirName/ or fileName
- QMultiMap<QString, QString> validPaths {
- { manifestDirectory()->absolutePath(), QString() }
- };
- for (const InstallationLocation &il : qAsConst(d->installationLocations)) {
- validPaths.insert(il.documentPath(), QString());
- validPaths.insert(il.installationPath(), QString());
- }
-
- const auto allApps = am->applications();
- for (AbstractApplication *app : allApps) {
- const InstallationReport *ir = app->nonAliasedInfo()->installationReport();
- if (ir) {
- const InstallationLocation &il = installationLocationFromId(ir->installationLocationId());
-
- bool valid = il.isValid();
-
- if (!valid)
- qCDebug(LogInstaller) << "cleanup: uninstalling" << app->id() << "- installationLocation is invalid";
-
- if (valid) {
- QStringList checkDirs;
- QStringList checkFiles;
-
- checkDirs << manifestDirectory()->absoluteFilePath(app->id());
- checkFiles << manifestDirectory()->absoluteFilePath(app->id()) + qSL("/info.yaml");
- checkFiles << manifestDirectory()->absoluteFilePath(app->id()) + qSL("/installation-report.yaml");
- checkDirs << il.documentPath() + app->id();
- checkDirs << il.installationPath() + app->id();
-
- for (const QString &checkFile : qAsConst(checkFiles)) {
- QFileInfo fi(checkFile);
- if (!fi.exists() || !fi.isFile() || !fi.isReadable()) {
- valid = false;
- qCDebug(LogInstaller) << "cleanup: uninstalling" << app->id() << "- file missing:" << checkFile;
- break;
- }
- }
- for (const QString &checkDir : checkDirs) {
- QFileInfo fi(checkDir);
- if (!fi.exists() || !fi.isDir() || !fi.isReadable()) {
- valid = false;
- qCDebug(LogInstaller) << "cleanup: uninstalling" << app->id() << "- directory missing:" << checkDir;
- break;
- }
- }
-
- if (valid) {
- validPaths.insertMulti(il.installationPath(), app->id() + qL1C('/'));
- validPaths.insertMulti(il.documentPath(), app->id() + qL1C('/'));
- validPaths.insertMulti(manifestDirectory()->absolutePath(), app->id() + qL1C('/'));
- }
- }
- if (!valid) {
- if (am->startingApplicationRemoval(app->id())) {
- if (am->finishedApplicationInstall(app->id()))
- continue;
- }
- throw Exception(Error::Package, "could not remove broken installation of app %1 from database").arg(app->id());
- }
- }
- }
-
- // Remove everything that is not referenced from the app-db
-
- for (auto it = validPaths.cbegin(); it != validPaths.cend(); ) {
- const QString currentDir = it.key();
-
- // collect all values for the unique key currentDir
- QVector<QString> validNames;
- for ( ; it != validPaths.cend() && it.key() == currentDir; ++it)
- validNames << it.value();
-
- const QFileInfoList &dirEntries = QDir(currentDir).entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot);
-
- // check if there is anything in the filesystem that is NOT listed in the validNames
- for (const QFileInfo &fi : dirEntries) {
- QString name = fi.fileName();
- if (fi.isDir())
- name.append(qL1C('/'));
-
- if ((!fi.isDir() && !fi.isFile()) || !validNames.contains(name)) {
- qCDebug(LogInstaller) << "cleanup: removing unreferenced inode" << name;
-
- if (SudoClient::instance()) {
- if (!SudoClient::instance()->removeRecursive(fi.absoluteFilePath()))
- throw Exception(Error::IO, "could not remove broken installation leftover %1 : %2").arg(fi.absoluteFilePath()).arg(SudoClient::instance()->lastError());
- } else {
- if (!recursiveOperation(fi.absoluteFilePath(), safeRemove))
- throw Exception(Error::IO, "could not remove broken installation leftover %1 (maybe due to missing root privileges)").arg(fi.absoluteFilePath());
- }
- }
- }
- }
-}
-
-QVector<InstallationLocation> ApplicationInstaller::installationLocations() const
-{
- return d->installationLocations;
-}
-
-
-const InstallationLocation &ApplicationInstaller::defaultInstallationLocation() const
-{
- static bool once = false;
- static int defaultIndex = -1;
-
- if (!once) {
- for (int i = 0; i < d->installationLocations.size(); ++i) {
- if (d->installationLocations.at(i).isDefault()) {
- defaultIndex = i;
- break;
- }
- }
- once = true;
- }
- return (defaultIndex < 0) ? d->invalidInstallationLocation : d->installationLocations.at(defaultIndex);
-}
-
-const InstallationLocation &ApplicationInstaller::installationLocationFromId(const QString &installationLocationId) const
-{
- for (const InstallationLocation &il : d->installationLocations) {
- if (il.id() == installationLocationId)
- return il;
- }
- return d->invalidInstallationLocation;
-}
-
-const InstallationLocation &ApplicationInstaller::installationLocationFromApplication(const QString &id) const
-{
- if (AbstractApplication *a = ApplicationManager::instance()->fromId(id)) {
- if (const InstallationReport *report = a->nonAliasedInfo()->installationReport())
- return installationLocationFromId(report->installationLocationId());
- }
- return d->invalidInstallationLocation;
-}
-
-
-/*!
- \qmlmethod list<string> ApplicationInstaller::installationLocationIds()
-
- Retuns a list of all known installation location ids. Calling getInstallationLocation() on one of
- the returned identifiers will yield specific information about the individual installation locations.
-*/
-QStringList ApplicationInstaller::installationLocationIds() const
-{
- QStringList ids;
- ids.reserve(d->installationLocations.size());
- for (const InstallationLocation &il : d->installationLocations)
- ids << il.id();
- return ids;
-}
-
-/*!
- \qmlmethod string ApplicationInstaller::installationLocationIdFromApplication(string id)
-
- Returns the installation location id for the application identified by \a id. Returns
- an empty string in case the application is not installed.
-
- \sa installationLocationIds()
- */
-QString ApplicationInstaller::installationLocationIdFromApplication(const QString &id) const
-{
- const InstallationLocation &il = installationLocationFromApplication(id);
- return il.isValid() ? il.id() : QString();
-}
-
-/*!
- \qmlmethod object ApplicationInstaller::getInstallationLocation(string installationLocationId)
-
- Returns an object describing the installation location identified by \a installationLocationId in detail.
-
- The returned object has the following members:
-
- \table
- \header
- \li \c Name
- \li \c Type
- \li Description
- \row
- \li \c id
- \li \c string
- \li The installation location id that is used as the handle for all other ApplicationInstaller
- function calls. The \c id consists of the \c type and \c index field, concatenated by
- a single dash (for example, \c internal-0).
- \row
- \li \c type
- \li \c string
- \li The type of device this installation location is connected to. Valid values are \c
- internal (for any kind of built-in storage, e.g. flash), \c removable (for any kind of
- storage that is removable by the user, e.g. an SD card) and \c invalid.
- \row
- \li \c index
- \li \c int
- \li In case there is more than one installation location for the same type of device, this
- \c zero-based index is used for disambiguation. For example, two SD card slots will
- result in the ids \c removable-0 and \c removable-1. Otherwise, the index is always \c 0.
- \row
- \li \c isDefault
- \li \c bool
-
- \li Exactly one installation location is the default location which must be mounted and
- accessible at all times. This can be used by an UI application to get a sensible
- default for the installation location that it needs to pass to startPackageInstallation().
- \row
- \li \c isRemovable
- \li \c bool
- \li Indicates whether this installation location is on a removable media (for example, an SD
- card).
- \row
- \li \c isMounted
- \li \c bool
- \li The current mount status of this installation location: should always be \c true for
- non-removable media.
- \row
- \li \c installationPath
- \li \c string
- \li The absolute file-system path to the base directory under which applications are installed.
- \row
- \li \c installationDeviceSize
- \li \c int
- \li The size of the device holding \c installationPath in bytes. This field is only present if
- \c isMounted is \c true.
- \row
- \li \c installationDeviceFree
- \li \c int
- \li The amount of bytes available on the device holding \c installationPath. This field is only
- present if \c isMounted is \c true.
- \row
- \li \c documentPath
- \li \c string
- \li The absolute file-system path to the base directory under which per-user document
- directories are created.
- \row
- \li \c documentDeviceSize
- \li \c int
- \li The size of the device holding \c documentPath in bytes. This field is only present if
- \c isMounted is \c true.
- \row
- \li \c documentDeviceFree
- \li \c int
- \li The amount of bytes available on the device holding \c documentPath. This field is only
- present if \c isMounted is \c true.
- \endtable
-
- Returns an empty object in case the \a installationLocationId is not valid.
-*/
-QVariantMap ApplicationInstaller::getInstallationLocation(const QString &installationLocationId) const
-{
- const InstallationLocation &il = installationLocationFromId(installationLocationId);
- return il.isValid() ? il.toVariantMap() : QVariantMap();
-}
-
-/*!
- \qmlmethod int ApplicationInstaller::installedApplicationSize(string id)
-
- Returns the size in bytes that the application identified by \a id is occupying on the storage
- device.
-
- Returns \c -1 in case the application \a id is not valid, or the application is not installed.
-*/
-qint64 ApplicationInstaller::installedApplicationSize(const QString &id) const
-{
- if (AbstractApplication *a = ApplicationManager::instance()->fromId(id)) {
- if (const InstallationReport *report = a->nonAliasedInfo()->installationReport())
- return static_cast<qint64>(report->diskSpaceUsed());
- }
- return -1;
-}
-
-/*!
- \qmlmethod var ApplicationInstaller::installedApplicationExtraMetaData(string id)
-
- Returns a map of all extra metadata in the package header of the application identified by \a id.
-
- Returns an empty map in case the application \a id is not valid, or the application is not installed.
-*/
-QVariantMap ApplicationInstaller::installedApplicationExtraMetaData(const QString &id) const
-{
- if (AbstractApplication *a = ApplicationManager::instance()->fromId(id)) {
- if (const InstallationReport *report = a->nonAliasedInfo()->installationReport())
- return report->extraMetaData();
- }
- return QVariantMap();
-}
-
-/*!
- \qmlmethod var ApplicationInstaller::installedApplicationExtraSignedMetaData(string id)
-
- Returns a map of all signed extra metadata in the package header of the application identified
- by \a id.
-
- Returns an empty map in case the application \a id is not valid, or the application is not installed.
-*/
-QVariantMap ApplicationInstaller::installedApplicationExtraSignedMetaData(const QString &id) const
-{
- if (AbstractApplication *a = ApplicationManager::instance()->fromId(id)) {
- if (const InstallationReport *report = a->nonAliasedInfo()->installationReport())
- return report->extraSignedMetaData();
- }
- return QVariantMap();
-}
-
-/*! \internal
- Type safe convenience function, since DBus does not like QUrl
-*/
-QString ApplicationInstaller::startPackageInstallation(const QString &installationLocationId, const QUrl &sourceUrl)
-{
- AM_TRACE(LogInstaller, installationLocationId, sourceUrl);
-
- const InstallationLocation &il = installationLocationFromId(installationLocationId);
-
- return enqueueTask(new InstallationTask(il, sourceUrl));
-}
-
-/*!
- \qmlmethod string ApplicationInstaller::startPackageInstallation(string installationLocationId, string sourceUrl)
-
- Downloads an application package from \a sourceUrl and installs it to the installation location
- described by \a installationLocationId.
-
- The actual download and installation will happen asynchronously in the background. The
- ApplicationInstaller emits the signals \l taskStarted, \l taskProgressChanged, \l
- taskRequestingInstallationAcknowledge, \l taskFinished, \l taskFailed, and \l taskStateChanged
- for the returned taskId when applicable.
-
- \note Simply calling this function is not enough to complete a package installation: The
- taskRequestingInstallationAcknowledge() signal needs to be connected to a slot where the
- supplied application meta-data can be validated (either programmatically or by asking the user).
- If the validation is successful, the installation can be completed by calling
- acknowledgePackageInstallation() or, if the validation was unsuccessful, the installation should
- be canceled by calling cancelTask().
- Failing to do one or the other will leave an unfinished "zombie" installation.
-
- Returns a unique \c taskId. This can also be an empty string, if the task could not be
- created (in this case, no signals will be emitted).
-*/
-QString ApplicationInstaller::startPackageInstallation(const QString &installationLocationId, const QString &sourceUrl)
-{
- QUrl url(sourceUrl);
- if (url.scheme().isEmpty())
- url = QUrl::fromLocalFile(sourceUrl);
- return startPackageInstallation(installationLocationId, url);
-}
-
-/*!
- \qmlmethod void ApplicationInstaller::acknowledgePackageInstallation(string taskId)
-
- Calling this function enables the installer to complete the installation task identified by \a
- taskId. Normally, this function is called after receiving the taskRequestingInstallationAcknowledge()
- signal, and the user and/or the program logic decided to proceed with the installation.
-
- \sa startPackageInstallation()
- */
-void ApplicationInstaller::acknowledgePackageInstallation(const QString &taskId)
-{
- AM_TRACE(LogInstaller, taskId)
-
- const auto allTasks = d->allTasks();
-
- for (AsynchronousTask *task : allTasks) {
- if (qobject_cast<InstallationTask *>(task) && (task->id() == taskId)) {
- static_cast<InstallationTask *>(task)->acknowledge();
- break;
- }
- }
-}
-
-/*!
- \qmlmethod string ApplicationInstaller::removePackage(string id, bool keepDocuments, bool force)
-
- Uninstalls the application identified by \a id. Normally, the documents directory of the
- application is deleted on removal, but this can be prevented by setting \a keepDocuments to \c true.
-
- The actual removal will happen asynchronously in the background. The ApplicationInstaller will
- emit the signals \l taskStarted, \l taskProgressChanged, \l taskFinished, \l taskFailed and \l
- taskStateChanged for the returned \c taskId when applicable.
-
- Normally, \a force should only be set to \c true if a previous call to removePackage() failed.
- This may be necessary if the installation process was interrupted, or if an SD card got lost
- or has file-system issues.
-
- Returns a unique \c taskId. This can also be an empty string, if the task could not be created
- (in this case, no signals will be emitted).
-*/
-QString ApplicationInstaller::removePackage(const QString &id, bool keepDocuments, bool force)
-{
- AM_TRACE(LogInstaller, id, keepDocuments)
-
- if (AbstractApplication *a = ApplicationManager::instance()->fromId(id)) {
- if (const InstallationReport *report = a->nonAliasedInfo()->installationReport()) {
- const InstallationLocation &il = installationLocationFromId(report->installationLocationId());
-
- if (il.isValid() && (il.id() == report->installationLocationId()))
- return enqueueTask(new DeinstallationTask(a->nonAliasedInfo(), il, force, keepDocuments));
- }
- }
- return QString();
-}
-
-
-/*!
- \qmlmethod enumeration ApplicationInstaller::taskState(string taskId)
-
- Returns the current state of the installation task identified by \a taskId.
- \l {TaskStates}{See here} for a list of valid task states.
-
- Returns \c ApplicationInstaller.Invalid if the \a taskId is invalid.
-*/
-AsynchronousTask::TaskState ApplicationInstaller::taskState(const QString &taskId) const
-{
- const auto allTasks = d->allTasks();
-
- for (const AsynchronousTask *task : allTasks) {
- if (task && (task->id() == taskId))
- return task->state();
- }
- return AsynchronousTask::Invalid;
-}
-
-/*!
- \qmlmethod string ApplicationInstaller::taskApplicationId(string taskId)
-
- Returns the application id associated with the task identified by \a taskId. The task may not
- have a valid application id at all times though and in this case the function will return an
- empty string (this will be the case for installations before the taskRequestingInstallationAcknowledge
- signal has been emitted).
-
- Returns an empty string if the \a taskId is invalid.
-*/
-QString ApplicationInstaller::taskApplicationId(const QString &taskId) const
-{
- const auto allTasks = d->allTasks();
-
- for (const AsynchronousTask *task : allTasks) {
- if (task && (task->id() == taskId))
- return task->applicationId();
- }
- return QString();
-}
-
-/*!
- \qmlmethod list<string> ApplicationInstaller::activeTaskIds()
-
- Retuns a list of all currently active (as in not yet finished or failed) installation task ids.
-*/
-QStringList ApplicationInstaller::activeTaskIds() const
-{
- const auto allTasks = d->allTasks();
-
- QStringList result;
- for (const AsynchronousTask *task : allTasks)
- result << task->id();
- return result;
-}
-
-/*!
- \qmlmethod bool ApplicationInstaller::cancelTask(string taskId)
-
- Tries to cancel the installation task identified by \a taskId.
-
- Returns \c true if the task was canceled, \c false otherwise.
-*/
-bool ApplicationInstaller::cancelTask(const QString &taskId)
-{
- AM_TRACE(LogInstaller, taskId)
-
- // incoming tasks can be forcefully cancelled right away
- for (AsynchronousTask *task : qAsConst(d->incomingTaskList)) {
- if (task->id() == taskId) {
- task->forceCancel();
- task->deleteLater();
-
- handleFailure(task);
-
- d->incomingTaskList.removeOne(task);
- triggerExecuteNextTask();
- return true;
- }
- }
-
- // the active task and async tasks might be in a state where cancellation is not possible,
- // so we have to ask them nicely
- if (d->activeTask && d->activeTask->id() == taskId)
- return d->activeTask->cancel();
-
- for (AsynchronousTask *task : qAsConst(d->installationTaskList)) {
- if (task->id() == taskId)
- return task->cancel();
- }
- return false;
-}
-
-/*!
- \qmlmethod int ApplicationInstaller::compareVersions(string version1, string version2)
-
- Convenience method for app-store implementations or taskRequestingInstallationAcknowledge()
- callbacks for comparing version numbers, as the actual version comparison algorithm is not
- trivial.
-
- Returns \c -1, \c 0 or \c 1 if \a version1 is smaller than, equal to, or greater than \a
- version2 (similar to how \c strcmp() works).
-*/
-int ApplicationInstaller::compareVersions(const QString &version1, const QString &version2)
-{
- int pos1 = 0;
- int pos2 = 0;
- int len1 = version1.length();
- int len2 = version2.length();
-
- forever {
- if (pos1 == len1 && pos2 == len2)
- return 0;
- else if (pos1 >= len1)
- return -1;
- else if (pos2 >= len2)
- return +1;
-
- QString part1 = version1.mid(pos1++, 1);
- QString part2 = version2.mid(pos2++, 1);
-
- bool isDigit1 = part1.at(0).isDigit();
- bool isDigit2 = part2.at(0).isDigit();
-
- if (!isDigit1 || !isDigit2) {
- int cmp = part1.compare(part2);
- if (cmp)
- return (cmp > 0) ? 1 : -1;
- } else {
- while ((pos1 < len1) && version1.at(pos1).isDigit())
- part1.append(version1.at(pos1++));
- while ((pos2 < len2) && version2.at(pos2).isDigit())
- part2.append(version2.at(pos2++));
-
- int num1 = part1.toInt();
- int num2 = part2.toInt();
-
- if (num1 != num2)
- return (num1 > num2) ? 1 : -1;
- }
- }
-}
-
-/*!
- \qmlmethod int ApplicationInstaller::validateDnsName(string name, int minimalPartCount)
-
- Convenience method for app-store implementations or taskRequestingInstallationAcknowledge()
- callbacks for checking if the given \a name is a valid DNS (or reverse-DNS) name according to
- RFC 1035/1123. If the optional parameter \a minimalPartCount is specified, this function will
- also check if \a name contains at least this amount of parts/sub-domains.
-
- Returns \c true if the name is a valid DNS name or \c false otherwise.
-*/
-bool ApplicationInstaller::validateDnsName(const QString &name, int minimalPartCount)
-{
- try {
- // check if we have enough parts: e.g. "tld.company.app" would have 3 parts
- QStringList parts = name.split('.');
- if (parts.size() < minimalPartCount) {
- throw Exception(Error::Parse, "the minimum amount of parts (subdomains) is %1 (found %2)")
- .arg(minimalPartCount).arg(parts.size());
- }
-
- // standard RFC compliance tests (RFC 1035/1123)
-
- auto partCheck = [](const QString &part) {
- int len = part.length();
-
- if (len < 1 || len > 63)
- throw Exception(Error::Parse, "domain parts must consist of at least 1 and at most 63 characters (found %2 characters)").arg(len);
-
- for (int pos = 0; pos < len; ++pos) {
- ushort ch = part.at(pos).unicode();
- bool isFirst = (pos == 0);
- bool isLast = (pos == (len - 1));
- bool isDash = (ch == '-');
- bool isDigit = (ch >= '0' && ch <= '9');
- bool isLower = (ch >= 'a' && ch <= 'z');
-
- if ((isFirst || isLast || !isDash) && !isDigit && !isLower)
- throw Exception(Error::Parse, "domain parts must consist of only the characters '0-9', 'a-z', and '-' (which cannot be the first or last character)");
- }
- };
-
- for (const QString &part : parts)
- partCheck(part);
-
- return true;
- } catch (const Exception &e) {
- qCDebug(LogInstaller).noquote() << "validateDnsName failed:" << e.errorString();
- return false;
- }
-}
-
-QString ApplicationInstaller::enqueueTask(AsynchronousTask *task)
-{
- d->incomingTaskList.append(task);
- triggerExecuteNextTask();
- return task->id();
-}
-
-void ApplicationInstaller::triggerExecuteNextTask()
-{
- if (!QMetaObject::invokeMethod(this, "executeNextTask", Qt::QueuedConnection))
- qCCritical(LogSystem) << "ERROR: failed to invoke method checkQueue";
-}
-
-void ApplicationInstaller::executeNextTask()
-{
- if (d->activeTask || d->incomingTaskList.isEmpty())
- return;
-
- AsynchronousTask *task = d->incomingTaskList.takeFirst();
-
- if (task->hasFailed()) {
- task->setState(AsynchronousTask::Failed);
-
- handleFailure(task);
-
- task->deleteLater();
- triggerExecuteNextTask();
- return;
- }
-
- connect(task, &AsynchronousTask::started, this, [this, task]() {
- emit taskStarted(task->id());
- });
-
- connect(task, &AsynchronousTask::stateChanged, this, [this, task](AsynchronousTask::TaskState newState) {
- emit taskStateChanged(task->id(), newState);
- });
-
- connect(task, &AsynchronousTask::progress, this, [this, task](qreal p) {
- emit taskProgressChanged(task->id(), p);
- QMetaObject::invokeMethod(ApplicationManager::instance(),
- "progressingApplicationInstall",
- Qt::DirectConnection,
- Q_ARG(QString, task->applicationId()),
- Q_ARG(double, p));
- });
-
- connect(task, &AsynchronousTask::finished, this, [this, task]() {
- task->setState(task->hasFailed() ? AsynchronousTask::Failed : AsynchronousTask::Finished);
-
- if (task->hasFailed()) {
- handleFailure(task);
- } else {
- qCDebug(LogInstaller) << "emit finished" << task->id();
- emit taskFinished(task->id());
- }
-
- if (d->activeTask == task)
- d->activeTask = nullptr;
- d->installationTaskList.removeOne(task);
-
- delete task;
- triggerExecuteNextTask();
- });
-
- if (qobject_cast<InstallationTask *>(task)) {
- connect(static_cast<InstallationTask *>(task), &InstallationTask::finishedPackageExtraction, this, [this, task]() {
- qCDebug(LogInstaller) << "emit blockingUntilInstallationAcknowledge" << task->id();
- emit taskBlockingUntilInstallationAcknowledge(task->id());
-
- // we can now start the next download in parallel - the InstallationTask will take care
- // of serializing the final installation steps on its own as soon as it gets the
- // required acknowledge (or cancel).
- if (d->activeTask == task)
- d->activeTask = nullptr;
- d->installationTaskList.append(task);
- triggerExecuteNextTask();
- });
- }
-
-
- d->activeTask = task;
- task->setState(AsynchronousTask::Executing);
- task->start();
-}
-
-void ApplicationInstaller::handleFailure(AsynchronousTask *task)
-{
- qCDebug(LogInstaller) << "emit failed" << task->id() << task->errorCode() << task->errorString();
- emit taskFailed(task->id(), int(task->errorCode()), task->errorString());
-}
-
-
-bool removeRecursiveHelper(const QString &path)
-{
- if (ApplicationInstaller::instance()->isApplicationUserIdSeparationEnabled() && SudoClient::instance())
- return SudoClient::instance()->removeRecursive(path);
- else
- return recursiveOperation(path, safeRemove);
-}
-
-QT_END_NAMESPACE_AM
diff --git a/src/installer-lib/installationlocation.cpp b/src/installer-lib/installationlocation.cpp
deleted file mode 100644
index d87383f7..00000000
--- a/src/installer-lib/installationlocation.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Luxoft Sweden AB
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Luxoft Application Manager.
-**
-** $QT_BEGIN_LICENSE:LGPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** 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-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: LGPL-3.0
-**
-****************************************************************************/
-
-#include <QDir>
-
-#include "installationlocation.h"
-#include "global.h"
-#include "utilities.h"
-#include "exception.h"
-
-#if defined(Q_OS_WIN)
-# include <windows.h>
-#else
-# include <sys/stat.h>
-# include <errno.h>
-# if defined(Q_OS_ANDROID)
-# include <sys/vfs.h>
-# define statvfs statfs
-# else
-# include <sys/statvfs.h>
-# endif
-#endif
-
-QT_BEGIN_NAMESPACE_AM
-
-static QString fixPath(const QString &path, const QString &hardwareId)
-{
- QString realPath = path;
- realPath.replace(qL1S("@HARDWARE-ID@"), hardwareId);
- QDir dir(realPath);
- return (dir.exists() ? dir.canonicalPath() : dir.absolutePath()) + qL1C('/');
-}
-
-static bool diskUsage(const QString &path, quint64 *bytesTotal, quint64 *bytesFree)
-{
- QString cpath = QFileInfo(path).canonicalPath();
-
-#if defined(Q_OS_WIN)
- return GetDiskFreeSpaceExW((LPCWSTR) cpath.utf16(), (ULARGE_INTEGER *) bytesFree,
- (ULARGE_INTEGER *) bytesTotal, nullptr);
-
-#else // Q_OS_UNIX
- int result;
- struct ::statvfs svfs;
-
- do {
- result = ::statvfs(cpath.toLocal8Bit(), &svfs);
- if (result == -1 && errno == EINTR)
- continue;
- } while (false);
-
- if (result == 0) {
- if (bytesTotal)
- *bytesTotal = quint64(svfs.f_frsize) * svfs.f_blocks;
- if (bytesFree)
- *bytesFree = quint64(svfs.f_frsize) * svfs.f_bavail;
- return true;
- }
- return false;
-#endif // Q_OS_WIN
-}
-
-
-bool InstallationLocation::operator==(const InstallationLocation &other) const
-{
- return (m_valid == other.m_valid)
- && (m_index == other.m_index)
- && (m_installationPath == other.m_installationPath)
- && (m_documentPath == other.m_documentPath);
-}
-
-QString InstallationLocation::id() const
-{
- QString name = m_valid ? qSL("internal") : qSL("invalid");
- if (m_valid)
- name = name + QLatin1Char('-') + QString::number(m_index);
- return name;
-}
-
-int InstallationLocation::index() const
-{
- return m_index;
-}
-
-bool InstallationLocation::isValid() const
-{
- return m_valid;
-}
-
-bool InstallationLocation::isDefault() const
-{
- return m_isDefault;
-}
-
-QString InstallationLocation::installationPath() const
-{
- return m_installationPath;
-}
-
-QString InstallationLocation::documentPath() const
-{
- return m_documentPath;
-}
-
-bool InstallationLocation::installationDeviceFreeSpace(quint64 *bytesTotal, quint64 *bytesFree) const
-{
- return diskUsage(installationPath(), bytesTotal, bytesFree);
-}
-
-bool InstallationLocation::documentDeviceFreeSpace(quint64 *bytesTotal, quint64 *bytesFree) const
-{
- return diskUsage(documentPath(), bytesTotal, bytesFree);
-}
-
-QVariantMap InstallationLocation::toVariantMap() const
-{
- QVariantMap map;
- map[qSL("id")] = id();
- map[qSL("type")] = m_valid ? qSL("internal") : qSL("invalid");
- map[qSL("index")] = index();
- map[qSL("installationPath")] = installationPath();
- map[qSL("documentPath")] = documentPath();
- map[qSL("isDefault")] = isDefault();
-
- quint64 total = 0, free = 0;
- installationDeviceFreeSpace(&total, &free);
-
- map[qSL("installationDeviceSize")] = total;
- map[qSL("installationDeviceFree")] = free;
-
- total = free = 0;
- documentDeviceFreeSpace(&total, &free);
-
- map[qSL("documentDeviceSize")] = total;
- map[qSL("documentDeviceFree")] = free;
-
- return map;
-}
-
-QVector<InstallationLocation> InstallationLocation::parseInstallationLocations(const QVariantList &list,
- const QString &hardwareId) Q_DECL_NOEXCEPT_EXPR(false)
-{
- QVector<InstallationLocation> locations;
- bool gotDefault = false;
-
- for (const QVariant &v : list) {
- QVariantMap map = v.toMap();
-
- QString id = map.value(qSL("id")).toString();
- QString instPath = map.value(qSL("installationPath")).toString();
- QString documentPath = map.value(qSL("documentPath")).toString();
- bool isDefault = map.value(qSL("isDefault")).toBool();
-
- if (isDefault) {
- if (!gotDefault)
- gotDefault = true;
- else
- throw Exception(Error::Parse, "multiple default installation locations defined");
- }
-
- QString type = id.section('-', 0, 0);
- bool ok = false;
- int index = id.section('-', 1).toInt(&ok);
-
- if ((type == qSL("internal")) && (index >= 0) && ok) {
- InstallationLocation il;
- il.m_valid = true;
- il.m_index = index;
- il.m_installationPath = fixPath(instPath, hardwareId);
- il.m_documentPath = fixPath(documentPath, hardwareId);
- il.m_isDefault = isDefault;
-
- if (!QDir::root().mkpath(instPath)) {
- throw Exception(Error::Parse, "the app directory %2 for the installation location %1 does not exist")
- .arg(id).arg(instPath);
- }
- if (!QDir::root().mkpath(documentPath)) {
- throw Exception(Error::Parse, "the doc directory %2 for the installation location %1 does not exist")
- .arg(id).arg(documentPath);
- }
-
- locations.append(il);
- } else {
- throw Exception(Error::Parse, "could not parse the installation location with id %1").arg(id);
- }
- }
- return locations;
-}
-
-QT_END_NAMESPACE_AM
diff --git a/src/installer-lib/installer-lib.pro b/src/installer-lib/installer-lib.pro
deleted file mode 100644
index c61ad7fd..00000000
--- a/src/installer-lib/installer-lib.pro
+++ /dev/null
@@ -1,40 +0,0 @@
-TEMPLATE = lib
-TARGET = QtAppManInstaller
-MODULE = appman_installer
-
-load(am-config)
-
-QT = core network qml
-QT_FOR_PRIVATE *= \
- appman_common-private \
- appman_crypto-private \
- appman_application-private \
- appman_package-private \
- appman_manager-private
-
-CONFIG *= static internal_module
-CONFIG -= create_cmake
-
-include($$SOURCE_DIR/3rdparty/libarchive.pri)
-include($$SOURCE_DIR/3rdparty/libz.pri)
-
-HEADERS += \
- installationlocation.h \
- asynchronoustask.h \
- deinstallationtask.h \
- installationtask.h \
- scopeutilities.h \
- applicationinstaller.h \
- applicationinstaller_p.h \
- sudo.h \
-
-SOURCES += \
- installationlocation.cpp \
- asynchronoustask.cpp \
- installationtask.cpp \
- deinstallationtask.cpp \
- scopeutilities.cpp \
- applicationinstaller.cpp \
- sudo.cpp \
-
-load(qt_module)
diff --git a/src/intent-client-lib/intentclient.cpp b/src/intent-client-lib/intentclient.cpp
index 0c5d5264..89f4b949 100644
--- a/src/intent-client-lib/intentclient.cpp
+++ b/src/intent-client-lib/intentclient.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -253,7 +254,7 @@ void IntentClient::replyFromSystem(const QUuid &requestId, bool error, const QVa
if (it == m_waiting.cend()) {
qCWarning(LogIntents) << "IntentClient received an unexpected intent reply for request"
- << requestId << " succeeded:" << error << "error:"
+ << requestId << " succeeded:" << !error << "error:"
<< result.value(qL1S("errorMessage")).toString() << "result:" << result;
return;
}
diff --git a/src/intent-client-lib/intentclient.h b/src/intent-client-lib/intentclient.h
index aa4ed95a..f3ba44c2 100644
--- a/src/intent-client-lib/intentclient.h
+++ b/src/intent-client-lib/intentclient.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -102,8 +103,9 @@ private:
QList<IntentClientRequest *> m_waiting;
QMap<QPair<QString, QString>, IntentHandler *> m_handlers; // intentId + appId -> handler
- int m_replyFromSystemTimeout = 20000;
- int m_replyFromApplicationTimeout = 4000;
+ // no timeouts by default -- these have to be set at runtime
+ int m_replyFromSystemTimeout = 0;
+ int m_replyFromApplicationTimeout = 0;
IntentClientSystemInterface *m_systemInterface;
friend class IntentClientSystemInterface;
diff --git a/src/intent-client-lib/intentclientrequest.cpp b/src/intent-client-lib/intentclientrequest.cpp
index bee28543..c6cba1cb 100644
--- a/src/intent-client-lib/intentclientrequest.cpp
+++ b/src/intent-client-lib/intentclientrequest.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -333,20 +334,18 @@ void IntentClientRequest::setRequestId(const QUuid &requestId)
void IntentClientRequest::setResult(const QVariantMap &result)
{
- if (m_result != result) {
+ if (m_result != result)
m_result = result;
- m_succeeded = true;
- doFinish();
- }
+ m_succeeded = true;
+ doFinish();
}
void IntentClientRequest::setErrorMessage(const QString &errorMessage)
{
- if (m_errorMessage != errorMessage) {
+ if (m_errorMessage != errorMessage)
m_errorMessage = errorMessage;
- m_succeeded = false;
- doFinish();
- }
+ m_succeeded = false;
+ doFinish();
}
void IntentClientRequest::doFinish()
diff --git a/src/intent-client-lib/intentclientrequest.h b/src/intent-client-lib/intentclientrequest.h
index ce004c97..8d898d32 100644
--- a/src/intent-client-lib/intentclientrequest.h
+++ b/src/intent-client-lib/intentclientrequest.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/intent-client-lib/intentclientsysteminterface.cpp b/src/intent-client-lib/intentclientsysteminterface.cpp
index 420ee92a..9be9a140 100644
--- a/src/intent-client-lib/intentclientsysteminterface.cpp
+++ b/src/intent-client-lib/intentclientsysteminterface.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/intent-client-lib/intentclientsysteminterface.h b/src/intent-client-lib/intentclientsysteminterface.h
index 4baa33d4..307aae8f 100644
--- a/src/intent-client-lib/intentclientsysteminterface.h
+++ b/src/intent-client-lib/intentclientsysteminterface.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/intent-client-lib/intenthandler.cpp b/src/intent-client-lib/intenthandler.cpp
index 24579aef..a94b9902 100644
--- a/src/intent-client-lib/intenthandler.cpp
+++ b/src/intent-client-lib/intenthandler.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -95,7 +96,7 @@ QT_BEGIN_NAMESPACE_AM
registered for via its intentIds property.
Handling the request can be done synchronously or asynchronously. As soon as your handler has
either produced a result or detected an error condition, it should call either
- IntentClientRequest::sendReply() or IntentClientRequest::sendErrorReply respectively to send a
+ IntentRequest::sendReply() or IntentRequest::sendErrorReply respectively to send a
reply back to the requesting party.
Only the first call to one of these functions will have any effect. Any further invocations
will be ignored.
diff --git a/src/intent-client-lib/intenthandler.h b/src/intent-client-lib/intenthandler.h
index 650ea539..95c73e41 100644
--- a/src/intent-client-lib/intenthandler.h
+++ b/src/intent-client-lib/intenthandler.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/intent-server-lib/intent-server-lib.pro b/src/intent-server-lib/intent-server-lib.pro
index 19ebf29c..34519bfc 100644
--- a/src/intent-server-lib/intent-server-lib.pro
+++ b/src/intent-server-lib/intent-server-lib.pro
@@ -15,12 +15,14 @@ HEADERS += \
intent.h \
intentserver.h \
intentserverrequest.h \
- intentserversysteminterface.h
+ intentserversysteminterface.h \
+ intentmodel.h \
SOURCES += \
intent.cpp \
intentserver.cpp \
intentserverrequest.cpp \
- intentserversysteminterface.cpp
+ intentserversysteminterface.cpp \
+ intentmodel.cpp \
load(qt_module)
diff --git a/src/intent-server-lib/intent.cpp b/src/intent-server-lib/intent.cpp
index b1151910..72eff40b 100644
--- a/src/intent-server-lib/intent.cpp
+++ b/src/intent-server-lib/intent.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -44,48 +45,48 @@
#include <QRegularExpression>
#include <QVariant>
+#include <QLocale>
QT_BEGIN_NAMESPACE_AM
/*!
- \qmltype Intent
+ \qmltype IntentObject
\inqmlmodule QtApplicationManager.SystemUI
\ingroup system-ui-non-instantiable
\brief This type represents an Intent definition on the System-UI side.
- This is a QML gadget class representing a single Intent definition for a specific application.
+ This is a QML object class representing a single Intent definition for a specific application.
It is not creatable from QML code and all properties are read-only. Only functions and
- properties of IntentServer will return instances of this class.
+ properties of IntentServer will return pointers to this class.
*/
-/*! \qmlproperty bool Intent::valid
+/*! \qmlproperty string IntentObject::intentId
\readonly
- Set to \c true, if this instance reprensents a valid intent, or \c false otherwise.
+ The id of the intent.
*/
-/*! \qmlproperty string Intent::intentId
+/*! \qmlproperty string IntentObject::packageId
\readonly
- The id of the intent.
+ The id of the package that the handling application of this intent is part of.
*/
-/*! \qmlproperty string Intent::applicationId
+/*! \qmlproperty string IntentObject::applicationId
\readonly
- The id of the application that is handling this intent.
+ The id of the application responsible for handling this intent.
*/
-/*! \qmlproperty Intent.Visibility Intent::visibility
+/*! \qmlproperty IntentObject.Visibility IntentObject::visibility
\readonly
- The visibility of this intent for other applications.
+ The visibility of this intent for other packages.
\list
- \li Intent.Public - Any application can request this intent.
- \li Intent.Private - Only the handling application can request this intent (this will be more
- useful once application background services have been implemented).
+ \li IntentObject.Public - Any application can request this intent.
+ \li IntentObject.Private - Only applications from the same package can request this intent.
\endlist
*/
-/*! \qmlproperty list<string> Intent::requiredCapabilities
+/*! \qmlproperty list<string> IntentObject::requiredCapabilities
\readonly
An \l{ApplicationObject}{application} requesting this intent needs to have all of the given
capabilities.
@@ -93,56 +94,47 @@ QT_BEGIN_NAMESPACE_AM
\sa ApplicationObject::capabilities
*/
-/*! \qmlproperty var Intent::parameterMatch
+/*! \qmlproperty var IntentObject::parameterMatch
\readonly
- A handling application can limit what parameter values it accepts. One example would be an
- open-mime-type intent that is implemented by many applications: there would be a \c mimeType
- parameter and each application could limit the requests it wants to receive by setting a
- parameterMatch on this \c mimeType parameter, e.g. \c{{ mimeType: "^image/.*\.png$" }}
+ A handling application can limit what parameter values it accepts. The property itself is an
+ object that corresponds to a subset of allowed parameter object of this intent.
+ When set, the parameters of each incoming intent request are matched against this object,
+ following these rules:
+ \list
+ \li a field missing from \c parameterMatch is ignored.
+ \li a field of type \c string specified in \c parameterMatch is matched as a regular
+ expressions against the corresponding parameter value.
+ \li for fields of type \c list specified in \c parameterMatch, the corresponding parameter value
+ has to match any of the values in the list (using QVariant compare).
+ \li any other fields in \c parameterMatch are compared as QVariants to the corresponding
+ parameter value.
+ \endlist
+ One example would be an \c open-mime-type intent that is implemented by many applications: there
+ would be a \c mimeType parameter and each application could limit the requests it wants to
+ receive by setting a parameterMatch on this \c mimeType parameter, e.g.
+ \c{{ mimeType: "^image/.*\.png$" }}
*/
Intent::Intent()
{ }
-Intent::Intent(const Intent &other)
- : m_intentId(other.m_intentId)
- , m_visibility(other.m_visibility)
- , m_requiredCapabilities(other.m_requiredCapabilities)
- , m_parameterMatch(other.m_parameterMatch)
- , m_applicationId(other.m_applicationId)
- , m_backgroundHandlerId(other.m_backgroundHandlerId)
-{ }
-
-Intent::Intent(const QString &id, const QString &applicationId, const QString &backgroundHandlerId,
- const QStringList &capabilities, Intent::Visibility visibility, const QVariantMap &parameterMatch)
+Intent::Intent(const QString &id, const QString &packageId, const QString &applicationId,
+ const QStringList &capabilities, Intent::Visibility visibility,
+ const QVariantMap &parameterMatch, const QMap<QString, QString> &names,
+ const QUrl &icon, const QStringList &categories)
: m_intentId(id)
, m_visibility(visibility)
, m_requiredCapabilities(capabilities)
, m_parameterMatch(parameterMatch)
+ , m_packageId(packageId)
, m_applicationId(applicationId)
- , m_backgroundHandlerId(backgroundHandlerId)
-{ }
-
-Intent::operator bool() const
+ , m_categories(categories)
+ , m_icon(icon)
{
- return !m_intentId.isEmpty();
-}
-
-bool Intent::operator==(const Intent &other) const
-{
- return (m_intentId == other.m_intentId)
- && (m_visibility == other.m_visibility)
- && (m_requiredCapabilities == other.m_requiredCapabilities)
- && (m_parameterMatch == other.m_parameterMatch)
- && (m_applicationId == other.m_applicationId)
- && (m_backgroundHandlerId == other.m_backgroundHandlerId);
-}
-
-bool Intent::operator <(const Intent &other) const
-{
- return (m_intentId < other.m_intentId) ? true : (m_applicationId < other.m_applicationId);
+ for (auto it = names.cbegin(); it != names.cend(); ++it)
+ m_names.insert(it.key(), it.value());
}
QString Intent::intentId() const
@@ -165,14 +157,14 @@ QVariantMap Intent::parameterMatch() const
return m_parameterMatch;
}
-QString Intent::applicationId() const
+QString Intent::packageId() const
{
- return m_applicationId;
+ return m_packageId;
}
-QString Intent::backgroundServiceId() const
+QString Intent::applicationId() const
{
- return m_backgroundHandlerId;
+ return m_applicationId;
}
bool Intent::checkParameterMatch(const QVariantMap &parameters) const
@@ -200,7 +192,7 @@ bool Intent::checkParameterMatch(const QVariantMap &parameters) const
bool foundMatch = false;
const QVariantList rvlist = requiredValue.toList();
for (const QVariant &rv2 : rvlist) {
- if (actualValue.canConvert(rv2.type()) && actualValue == rv2) {
+ if (actualValue.canConvert(int(rv2.type())) && actualValue == rv2) {
foundMatch = true;
break;
}
@@ -219,4 +211,36 @@ bool Intent::checkParameterMatch(const QVariantMap &parameters) const
return true;
}
+QUrl Intent::icon() const
+{
+ return m_icon;
+}
+
+QString Intent::name() const
+{
+ QVariant name;
+ if (!m_names.isEmpty()) {
+ name = m_names.value(QLocale::system().name()); //TODO: language changes
+ if (name.isNull())
+ name = m_names.value(qSL("en"));
+ if (name.isNull())
+ name = m_names.value(qSL("en_US"));
+ if (name.isNull())
+ name = *m_names.constBegin();
+ } else {
+ name = intentId();
+ }
+ return name.toString();
+}
+
+QVariantMap Intent::names() const
+{
+ return m_names;
+}
+
+QStringList Intent::categories() const
+{
+ return m_categories;
+}
+
QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intent.h b/src/intent-server-lib/intent.h
index 0de7f4f1..a8a04d52 100644
--- a/src/intent-server-lib/intent.h
+++ b/src/intent-server-lib/intent.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -42,24 +43,31 @@
#pragma once
+#include <QObject>
#include <QString>
+#include <QUrl>
#include <QStringList>
#include <QVariantMap>
#include <QtAppManCommon/global.h>
QT_BEGIN_NAMESPACE_AM
-class Intent
+class Intent : public QObject
{
- Q_GADGET
- Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/Intent 2.0 UNCREATABLE")
+ Q_OBJECT
+ Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/IntentObject 2.0 UNCREATABLE")
- Q_PROPERTY(bool valid READ (operator bool))
- Q_PROPERTY(QString intentId READ intentId)
- Q_PROPERTY(QString applicationId READ applicationId)
- Q_PROPERTY(QT_PREPEND_NAMESPACE_AM(Intent)::Visibility visibility READ visibility)
- Q_PROPERTY(QStringList requiredCapabilities READ requiredCapabilities)
- Q_PROPERTY(QVariantMap parameterMatch READ parameterMatch)
+ Q_PROPERTY(QString intentId READ intentId CONSTANT)
+ Q_PROPERTY(QString packageId READ packageId CONSTANT)
+ Q_PROPERTY(QString applicationId READ applicationId CONSTANT)
+ Q_PROPERTY(QT_PREPEND_NAMESPACE_AM(Intent)::Visibility visibility READ visibility CONSTANT)
+ Q_PROPERTY(QStringList requiredCapabilities READ requiredCapabilities CONSTANT)
+ Q_PROPERTY(QVariantMap parameterMatch READ parameterMatch CONSTANT)
+
+ Q_PROPERTY(QUrl icon READ icon CONSTANT)
+ Q_PROPERTY(QString name READ name CONSTANT)
+ Q_PROPERTY(QVariantMap names READ names CONSTANT)
+ Q_PROPERTY(QStringList categories READ categories CONSTANT)
public:
enum Visibility {
@@ -69,38 +77,45 @@ public:
Q_ENUM(Visibility)
Intent();
- Intent(const Intent &other);
QString intentId() const;
Visibility visibility() const;
QStringList requiredCapabilities() const;
QVariantMap parameterMatch() const;
+ QString packageId() const;
QString applicationId() const;
- QString backgroundServiceId() const;
bool checkParameterMatch(const QVariantMap &parameters) const;
- explicit operator bool() const;
- bool operator ==(const Intent &other) const;
- bool operator <(const Intent &other) const; // need for QMetaType::registerComparators
+ QUrl icon() const;
+ QString name() const;
+ QVariantMap names() const;
+ QString description() const;
+ QVariantMap descriptions() const;
+ QStringList categories() const;
private:
- Intent(const QString &intentId, const QString &applicationId, const QString &backgroundHandlerId,
+ Intent(const QString &intentId, const QString &packageId, const QString &applicationId,
const QStringList &capabilities, Intent::Visibility visibility,
- const QVariantMap &parameterMatch = QVariantMap());
+ const QVariantMap &parameterMatch, const QMap<QString, QString> &names,
+ const QUrl &icon, const QStringList &categories);
QString m_intentId;
Visibility m_visibility = Private;
QStringList m_requiredCapabilities;
QVariantMap m_parameterMatch;
+ QString m_packageId;
QString m_applicationId;
- QString m_backgroundHandlerId;
+
+ QVariantMap m_names; // language -> name
+ QStringList m_categories;
+ QUrl m_icon;
friend class IntentServer;
};
QT_END_NAMESPACE_AM
-Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE_AM(Intent))
+Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE_AM(Intent *))
diff --git a/src/intent-server-lib/intentmodel.cpp b/src/intent-server-lib/intentmodel.cpp
new file mode 100644
index 00000000..4342fc9f
--- /dev/null
+++ b/src/intent-server-lib/intentmodel.cpp
@@ -0,0 +1,285 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QQmlContext>
+#include <QQmlEngine>
+#include <QQmlInfo>
+#include <QJSEngine>
+#include <QJSValueList>
+
+#include "global.h"
+#include "logging.h"
+#include "intentserver.h"
+#include "intentmodel.h"
+#include "intent.h"
+
+
+/*!
+ \qmltype IntentModel
+ \inherits QSortFilterProxyModel
+ \ingroup system-ui
+ \inqmlmodule QtApplicationManager.SystemUI
+ \brief A proxy model for the IntentServer singleton.
+
+ The IntentModel type provides a customizable model that can be used to tailor the
+ IntentServer model to your needs. The IntentServer singleton is a model itself,
+ that includes all available intents. In contrast, the IntentModel supports filtering
+ and sorting.
+
+ Since the IntentModel is based on the IntentServer model, the latter is referred
+ to as the \e source model. The IntentModel includes the same \l {IntentServer Roles}
+ {roles} as the IntentServer model.
+
+ \note If you require a model with all intents, with no filtering whatsoever, you should
+ use the IntentServer directly, as it has better performance.
+
+ The following code snippet displays the icons of all the intents belonging to the \c
+ com.pelagicore.test package:
+
+ \qml
+ import QtQuick 2.6
+ import QtApplicationManager.SystemUI 2.0
+
+ ListView {
+ model: IntentModel {
+ filterFunction: function(intent) {
+ return intent.packageId == 'com.pelagicore.test'
+ }
+ }
+
+ delegate: Image {
+ source: icon
+ }
+ }
+ \endqml
+*/
+
+/*!
+ \qmlproperty int IntentModel::count
+ \readonly
+
+ Holds the number of intents included in this model.
+*/
+
+/*!
+ \qmlproperty var IntentModel::filterFunction
+
+ A JavaScript function callback that is invoked for each intent in the IntentServer
+ source model. This function gets one IntentObject parameter and must return a Boolean.
+ If the intent passed should be included in this model, then the function must return
+ \c true; \c false otherwise.
+
+ If you need no filtering at all, you should set this property to an undefined (the default) or
+ null value.
+
+ \note Whenever this function is changed, the filter is reevaluated. Changes in the source model
+ are reflected. Since the type is derived from QSortFilterProxyModel, the
+ \l {QSortFilterProxyModel::invalidate()}{invalidate()} slot can be used to force a reevaluation.
+*/
+
+/*!
+ \qmlproperty var IntentModel::sortFunction
+
+ A JavaScript function callback that is invoked to sort the intents in this model. This function
+ gets two IntentObject parameters and must return a Boolean. If the first intent should have a
+ smaller index in this model than the second, the function must return \c true; \c false
+ otherwise.
+
+ If you need no sorting at all, you should set this property to an undefined (the default) or
+ null value.
+
+ \note Whenever this function is changed, the model is sorted. Changes in the source model are
+ reflected. Since the type is derived from QSortFilterProxyModel, the
+ \l {QSortFilterProxyModel::invalidate()}{invalidate()} slot can be used to force a sort.
+*/
+
+
+QT_BEGIN_NAMESPACE_AM
+
+
+class IntentModelPrivate
+{
+public:
+ QJSEngine *m_engine = nullptr;
+ QJSValue m_filterFunction;
+ QJSValue m_sortFunction;
+};
+
+
+IntentModel::IntentModel(QObject *parent)
+ : QSortFilterProxyModel(parent)
+ , d(new IntentModelPrivate())
+{
+ setSourceModel(IntentServer::instance());
+
+ connect(this, &QAbstractItemModel::rowsInserted, this, &IntentModel::countChanged);
+ connect(this, &QAbstractItemModel::rowsRemoved, this, &IntentModel::countChanged);
+ connect(this, &QAbstractItemModel::layoutChanged, this, &IntentModel::countChanged);
+ connect(this, &QAbstractItemModel::modelReset, this, &IntentModel::countChanged);
+}
+
+int IntentModel::count() const
+{
+ return rowCount();
+}
+
+bool IntentModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+{
+ Q_UNUSED(source_parent)
+
+ if (!d->m_engine)
+ d->m_engine = getJSEngine();
+ if (!d->m_engine)
+ qCWarning(LogSystem) << "IntentModel can't filter without a JavaScript engine";
+
+ if (d->m_engine && d->m_filterFunction.isCallable()) {
+ const QObject *intent = IntentServer::instance()->intent(source_row);
+ QJSValueList args = { d->m_engine->newQObject(const_cast<QObject*>(intent)) };
+ return d->m_filterFunction.call(args).toBool();
+ }
+
+ return true;
+}
+
+bool IntentModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
+{
+ if (!d->m_engine)
+ d->m_engine = getJSEngine();
+ if (!d->m_engine)
+ qCWarning(LogSystem) << "IntentModel can't sort without a JavaScript engine";
+
+ if (d->m_engine && d->m_sortFunction.isCallable()) {
+ const QObject *intent1 = IntentServer::instance()->intent(source_left.row());
+ const QObject *intent2 = IntentServer::instance()->intent(source_right.row());
+ QJSValueList args = { d->m_engine->newQObject(const_cast<QObject*>(intent1)),
+ d->m_engine->newQObject(const_cast<QObject*>(intent2)) };
+ return d->m_sortFunction.call(args).toBool();
+ }
+
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+}
+
+QJSValue IntentModel::filterFunction() const
+{
+ return d->m_filterFunction;
+}
+
+void IntentModel::setFilterFunction(const QJSValue &callback)
+{
+ if (!callback.equals(d->m_filterFunction)) {
+ d->m_filterFunction = callback;
+ emit filterFunctionChanged();
+ invalidateFilter();
+ }
+}
+
+QJSValue IntentModel::sortFunction() const
+{
+ return d->m_sortFunction;
+}
+
+void IntentModel::setSortFunction(const QJSValue &callback)
+{
+ if (!callback.equals(d->m_sortFunction)) {
+ d->m_sortFunction = callback;
+ emit sortFunctionChanged();
+ invalidate();
+ sort(0);
+ }
+}
+
+/*!
+ \qmlmethod int IntentModel::indexOfIntent(string intentId, string applicationId, var parameters)
+
+ Maps the intent corresponding to the given \a intentId, \a applicationId and \a parameters to
+ its position within this model. Returns \c -1 if the specified intent is invalid, or not part of
+ this model.
+*/
+int IntentModel::indexOfIntent(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters) const
+{
+ int idx = IntentServer::instance()->indexOfIntent(intentId, applicationId, parameters);
+ return idx != -1 ? mapFromSource(idx) : idx;
+}
+
+/*!
+ \qmlmethod int IntentModel::indexOfIntent(IntentObject intent)
+
+ Maps the \a intent to its position within this model. Returns \c -1 if the specified intent is
+ invalid, or not part of this model.
+*/
+int IntentModel::indexOfIntent(Intent *intent)
+{
+ int idx = IntentServer::instance()->indexOfIntent(intent);
+ return idx != -1 ? mapFromSource(idx) : idx;
+
+}
+
+/*!
+ \qmlmethod int IntentModel::mapToSource(int index)
+
+ Maps an intent's \a index in this model to the corresponding index in the
+ IntentServer model. Returns \c -1 if the specified \a index is invalid.
+*/
+int IntentModel::mapToSource(int ourIndex) const
+{
+ return QSortFilterProxyModel::mapToSource(index(ourIndex, 0)).row();
+}
+
+/*!
+ \qmlmethod int IntentModel::mapFromSource(int index)
+
+ Maps an intenet's \a index from the IntentServer model to the corresponding index in
+ this model. Returns \c -1 if the specified \a index is invalid.
+*/
+int IntentModel::mapFromSource(int sourceIndex) const
+{
+ return QSortFilterProxyModel::mapFromSource(sourceModel()->index(sourceIndex, 0)).row();
+}
+
+QJSEngine *IntentModel::getJSEngine() const
+{
+ QQmlContext *context = QQmlEngine::contextForObject(this);
+ return context ? reinterpret_cast<QJSEngine*>(context->engine()) : nullptr;
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intentmodel.h b/src/intent-server-lib/intentmodel.h
new file mode 100644
index 00000000..c8d7b257
--- /dev/null
+++ b/src/intent-server-lib/intentmodel.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QSortFilterProxyModel>
+#include <QJSValue>
+#include <QtAppManCommon/global.h>
+
+QT_FORWARD_DECLARE_CLASS(QJSEngine);
+
+QT_BEGIN_NAMESPACE_AM
+
+class Intent;
+class IntentModelPrivate;
+
+class IntentModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+ Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/IntentModel 2.0")
+
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(QJSValue filterFunction READ filterFunction WRITE setFilterFunction NOTIFY filterFunctionChanged)
+ Q_PROPERTY(QJSValue sortFunction READ sortFunction WRITE setSortFunction NOTIFY sortFunctionChanged)
+
+public:
+ IntentModel(QObject *parent = nullptr);
+
+ int count() const;
+
+ QJSValue filterFunction() const;
+ void setFilterFunction(const QJSValue &callback);
+
+ QJSValue sortFunction() const;
+ void setSortFunction(const QJSValue &callback);
+
+ Q_INVOKABLE int indexOfIntent(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters = {}) const;
+ Q_INVOKABLE int indexOfIntent(Intent *intent);
+ Q_INVOKABLE int mapToSource(int ourIndex) const;
+ Q_INVOKABLE int mapFromSource(int sourceIndex) const;
+
+protected:
+ using QSortFilterProxyModel::mapToSource;
+ using QSortFilterProxyModel::mapFromSource;
+
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
+ bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
+
+signals:
+ void countChanged();
+ void filterFunctionChanged();
+ void sortFunctionChanged();
+
+private:
+ QJSEngine *getJSEngine() const;
+
+ IntentModelPrivate *d;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intentserver.cpp b/src/intent-server-lib/intentserver.cpp
index 0ba11e2f..9a0603f3 100644
--- a/src/intent-server-lib/intentserver.cpp
+++ b/src/intent-server-lib/intentserver.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -43,6 +44,8 @@
#include "intentserver.h"
#include "intentserversysteminterface.h"
#include "intentserverrequest.h"
+#include "intentmodel.h"
+
#include <QtAppManCommon/logging.h>
#include <algorithm>
@@ -66,11 +69,58 @@ QT_BEGIN_NAMESPACE_AM
\brief The System-UI side singleton representing the Intents sub-system.
This singleton serves two purposes: for one, it gives the System-UI access to the database of
- all the available intents via intentList, plus it exposes the API to deal with ambigous intent
+ all the available intents via its item model API, plus it exposes the API to deal with ambigous intent
requests. Intent requests can be ambigous if the requesting party only specified the \c
intentId, but not the targeted \c applicationId in its call to
IntentClient::sendIntentRequest(). In these cases, it is the responsibility of the System-UI to
disambiguate these requests by reacting on the disambiguationRequest() signal.
+
+ The type is derived from \c QAbstractListModel, so it can be used directly
+ as a model in app-grid views.
+
+ \target IntentServer Roles
+
+ The following roles are available in this model:
+
+ \table
+ \header
+ \li Role name
+ \li Type
+ \li Description
+ \row
+ \li \c intentId
+ \li string
+ \li The id of the intent.
+ \row
+ \li \c packageId
+ \li string
+ \li The unique id of the package that the handling application of this intent is part of.
+ \row
+ \li \c applicationId
+ \li string
+ \li The id of the application responsible for handling this intent.
+ \row
+ \li \c name
+ \li string
+ \li The name of the intent. If possible, already translated to the current locale.
+ If no name was defined for the intent, the name of the corresponding package will be
+ returned.
+ \row
+ \li \c icon
+ \li string
+ \li The URL of the intent's icon.
+ If no icon was defined for the intent, the icon of the corresponding package will be
+ returned.
+ \row
+ \li \c categories
+ \li list<string>
+ \li The categories this intent is registered for via its meta-data file.
+ \row
+ \li \c intent
+ \li Intent
+ \li The underlying Intent object for quick access to the properties outside of a
+ model delegate.
+ \endtable
*/
/*! \qmlsignal IntentServer::intentAdded(Intent intent)
@@ -87,7 +137,20 @@ QT_BEGIN_NAMESPACE_AM
intentList.
*/
+enum Roles
+{
+ IntentId = Qt::UserRole,
+ ApplicationId,
+ PackageId,
+ ParameterMatch,
+ Name,
+ Icon,
+ Categories,
+ IntentItem
+};
+
IntentServer *IntentServer::s_instance = nullptr;
+QHash<int, QByteArray> IntentServer::s_roleNames;
IntentServer *IntentServer::createInstance(IntentServerSystemInterface *systemInterface)
{
@@ -99,15 +162,8 @@ IntentServer *IntentServer::createInstance(IntentServerSystemInterface *systemIn
QScopedPointer<IntentServer> is(new IntentServer(systemInterface));
systemInterface->initialize(is.data());
- qRegisterMetaType<Intent>("Intent");
- QMetaType::registerComparators<Intent>();
-
- // Have a nicer name in the C++ API, since QML cannot cope with QList<Q_GADGET-type>
- qRegisterMetaType<QVariantList>("IntentList");
-
- // needed to get access to the Visibility enum from QML
- qmlRegisterUncreatableType<Intent>("QtApplicationManager.SystemUI", 2, 0, "Intent",
- qSL("Cannot create objects of type Intent"));
+ qmlRegisterType<Intent>("QtApplicationManager.SystemUI", 2, 0, "IntentObject");
+ qmlRegisterType<IntentModel>("QtApplicationManager.SystemUI", 2, 0, "IntentModel");
qmlRegisterSingletonType<IntentServer>("QtApplicationManager.SystemUI", 2, 0, "IntentServer",
[](QQmlEngine *, QJSEngine *) -> QObject * {
@@ -140,12 +196,21 @@ void IntentServer::setReplyFromApplicationTimeout(int timeout)
}
IntentServer::IntentServer(IntentServerSystemInterface *systemInterface, QObject *parent)
- : QObject(parent)
+ : QAbstractListModel(parent)
, m_systemInterface(systemInterface)
{
m_systemInterface->setParent(this);
- connect(this, &IntentServer::intentAdded, this, &IntentServer::intentListChanged);
- connect(this, &IntentServer::intentRemoved, this, &IntentServer::intentListChanged);
+
+ if (s_roleNames.isEmpty()) {
+ s_roleNames.insert(IntentId, "intentId");
+ s_roleNames.insert(ApplicationId, "applicationId");
+ s_roleNames.insert(PackageId, "packageId");
+ s_roleNames.insert(ParameterMatch, "parameterMatch");
+ s_roleNames.insert(Name, "name");
+ s_roleNames.insert(Icon, "icon");
+ s_roleNames.insert(Categories, "categories");
+ s_roleNames.insert(IntentItem, "intent");
+ }
}
IntentServer::~IntentServer()
@@ -153,120 +218,120 @@ IntentServer::~IntentServer()
s_instance = nullptr;
}
-bool IntentServer::addApplication(const QString &applicationId)
+bool IntentServer::addPackage(const QString &packageId)
{
- if (m_knownApplications.contains(applicationId))
+ if (m_knownApplications.contains(packageId))
return false;
- m_knownApplications << applicationId;
+ m_knownApplications.insert(packageId, QStringList());
return true;
}
-void IntentServer::removeApplication(const QString &applicationId)
+void IntentServer::removePackage(const QString &packageId)
{
- m_knownBackgroundServices.remove(applicationId);
- m_knownApplications.removeOne(applicationId);
+ m_knownApplications.remove(packageId);
}
-bool IntentServer::addApplicationBackgroundHandler(const QString &applicationId, const QString &backgroundServiceId)
+bool IntentServer::addApplication(const QString &applicationId, const QString &packageId)
{
- if (!m_knownApplications.contains(applicationId))
+ if (!m_knownApplications.contains(packageId))
return false;
- const QStringList services = m_knownBackgroundServices.value(applicationId);
- if (services.contains(backgroundServiceId))
+ if (m_knownApplications.value(packageId).contains(applicationId))
return false;
- m_knownBackgroundServices[applicationId].append(backgroundServiceId);
+ m_knownApplications[packageId].append(applicationId);
return true;
}
-void IntentServer::removeApplicationBackgroundHandler(const QString &applicationId, const QString &backgroundServiceId)
-{
- m_knownBackgroundServices[applicationId].removeAll(backgroundServiceId);
-}
-
-Intent IntentServer::addIntent(const QString &id, const QString &applicationId,
- const QStringList &capabilities, Intent::Visibility visibility,
- const QVariantMap &parameterMatch)
+void IntentServer::removeApplication(const QString &applicationId, const QString &packageId)
{
- return addIntent(id, applicationId, QString(), capabilities, visibility, parameterMatch);
+ m_knownApplications[packageId].removeAll(applicationId);
}
-Intent IntentServer::addIntent(const QString &id, const QString &applicationId,
- const QString &backgroundHandlerId,
- const QStringList &capabilities, Intent::Visibility visibility,
- const QVariantMap &parameterMatch)
+Intent *IntentServer::addIntent(const QString &id, const QString &packageId,
+ const QString &handlingApplicationId,
+ const QStringList &capabilities, Intent::Visibility visibility,
+ const QVariantMap &parameterMatch, const QMap<QString, QString> &names,
+ const QUrl &icon, const QStringList &categories)
{
- if (id.isEmpty()
- || !m_knownApplications.contains(applicationId)
- || find(id, applicationId)
- || (!backgroundHandlerId.isEmpty()
- && !m_knownBackgroundServices[applicationId].contains(backgroundHandlerId))) {
- return Intent();
+ try {
+ if (id.isEmpty())
+ throw "no id specified";
+ if (packageId.isEmpty())
+ throw "no packageId specified";
+ if (handlingApplicationId.isEmpty())
+ throw "no handlingApplicationId specified";
+ if (!m_knownApplications.contains(packageId))
+ throw "packageId is not known";
+ if (!m_knownApplications.value(packageId).contains(handlingApplicationId))
+ throw "applicationId is not known or not part of the specified package";
+ if (applicationIntent(id, handlingApplicationId))
+ throw "intent with given id/handlingApplicationId already exists";
+ } catch (const char *e) {
+ qCWarning(LogIntents) << "Cannot add intent" << id << "in package" << packageId
+ << "handled by" << handlingApplicationId << ":" << e;
+ return nullptr;
}
- auto intent = Intent(id, applicationId, backgroundHandlerId, capabilities, visibility,
- parameterMatch);
+ auto intent = new Intent(id, packageId, handlingApplicationId, capabilities, visibility,
+ parameterMatch, names, icon, categories);
+ QQmlEngine::setObjectOwnership(intent, QQmlEngine::CppOwnership);
+
+ beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_intents << intent;
+ endInsertRows();
+
+ emit countChanged();
emit intentAdded(intent);
return intent;
}
-void IntentServer::removeIntent(const Intent &intent)
+void IntentServer::removeIntent(Intent *intent)
{
int index = m_intents.indexOf(intent);
if (index >= 0) {
+ emit intentAboutToBeRemoved(intent);
+ beginRemoveRows(QModelIndex(), index, index);
m_intents.removeAt(index);
- emit intentRemoved(intent);
- }
-}
+ endRemoveRows();
-QVector<Intent> IntentServer::all() const
-{
- return m_intents;
+ emit countChanged();
+ }
}
-QVector<Intent> IntentServer::filterByIntentId(const QVector<Intent> &intents, const QString &intentId,
- const QVariantMap &parameters) const
+QVector<Intent *> IntentServer::filterByIntentId(const QVector<Intent *> &intents, const QString &intentId,
+ const QVariantMap &parameters) const
{
- QVector<Intent> result;
+ QVector<Intent *> result;
std::copy_if(intents.cbegin(), intents.cend(), std::back_inserter(result),
- [intentId, parameters](const Intent &intent) -> bool {
- return (intent.intentId() == intentId) && intent.checkParameterMatch(parameters);
+ [intentId, parameters](Intent *intent) -> bool {
+ return (intent->intentId() == intentId) && intent->checkParameterMatch(parameters);
});
return result;
}
-QVector<Intent> IntentServer::filterByHandlingApplicationId(const QVector<Intent> &intents,
- const QString &handlingApplicationId,
- const QVariantMap &parameters) const
-{
- QVector<Intent> result;
- std::copy_if(intents.cbegin(), intents.cend(), std::back_inserter(result),
- [handlingApplicationId, parameters](const Intent &intent) -> bool {
- return (intent.applicationId() == handlingApplicationId) && intent.checkParameterMatch(parameters);
-
- });
- return result;
-}
-QVector<Intent> IntentServer::filterByRequestingApplicationId(const QVector<Intent> &intents,
- const QString &requestingApplicationId) const
+QVector<Intent *> IntentServer::filterByRequestingApplicationId(const QVector<Intent *> &intents,
+ const QString &requestingApplicationId) const
{
- QVector<Intent> result;
+ const QString requestingPackageId = packageIdForApplicationId(requestingApplicationId);
+
+ QVector<Intent *> result;
std::copy_if(intents.cbegin(), intents.cend(), std::back_inserter(result),
- [this, requestingApplicationId](const Intent &intent) -> bool {
+ [this, requestingPackageId, requestingApplicationId](Intent *intent) -> bool {
// filter on visibility and capabilities, if the requesting app is different from the
// handling app
- if (intent.applicationId() != requestingApplicationId) {
- if (intent.visibility() == Intent::Private) {
- qCDebug(LogIntents) << "Not considering" << intent.intentId() << "/" << intent.applicationId()
- << "due to private visibility";
+
+ if (intent->packageId() != requestingPackageId) {
+ if (intent->visibility() == Intent::Private) {
+ qCDebug(LogIntents) << "Not considering" << intent->intentId() << "in package"
+ << intent->packageId() << "due to private visibility";
return false;
- } else if (!intent.requiredCapabilities().isEmpty()
+ } else if (!intent->requiredCapabilities().isEmpty()
&& !m_systemInterface->checkApplicationCapabilities(requestingApplicationId,
- intent.requiredCapabilities())) {
- qCDebug(LogIntents) << "Not considering" << intent.intentId() << "/" << intent.applicationId()
- << "due to missing capabilities";
+ intent->requiredCapabilities())) {
+ qCDebug(LogIntents) << "Not considering" << intent->intentId() << "in package"
+ << intent->packageId()
+ << "due to missing capabilities of requesting application";
return false;
}
}
@@ -275,35 +340,181 @@ QVector<Intent> IntentServer::filterByRequestingApplicationId(const QVector<Inte
return result;
}
-/*! \qmlproperty list<Intent> IntentServer::intentList
+int IntentServer::rowCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? -1 : m_intents.count();
+}
+
+QVariant IntentServer::data(const QModelIndex &index, int role) const
+{
+ if (index.parent().isValid() || !index.isValid())
+ return QVariant();
+
+ Intent *intent = m_intents.at(index.row());
+
+ switch (role) {
+ case IntentId:
+ return intent->intentId();
+ case PackageId:
+ return intent->packageId();
+ case ApplicationId:
+ return intent->applicationId();
+ case ParameterMatch:
+ return intent->parameterMatch();
+ case Name:
+ return intent->name();
+ case Icon:
+ return intent->icon();
+ case Categories:
+ return intent->categories();
+ case IntentItem:
+ return QVariant::fromValue(intent);
+ }
+ return QVariant();
+}
+
+QHash<int, QByteArray> IntentServer::roleNames() const
+{
+ return s_roleNames;
+}
+
+int IntentServer::count() const
+{
+ return rowCount();
+}
- The list of all registered \l{Intent}{Intents} in the system.
+/*!
+ \qmlmethod object IntentServer::get(int index)
+
+ Retrieves the model data at \a index as a JavaScript object. See the
+ \l {IntentServer Roles}{role names} for the expected object fields.
+
+ Returns an empty object if the specified \a index is invalid.
+
+ \note This is very inefficient if you only want to access a single property from QML; use
+ intent() instead to access the Intent object's properties directly.
*/
+QVariantMap IntentServer::get(int index) const
+{
+ if (index < 0 || index >= count()) {
+ qCWarning(LogSystem) << "IntentServer::get(index): invalid index:" << index;
+ return QVariantMap();
+ }
-IntentList IntentServer::intentList() const
+ QVariantMap map;
+ QHash<int, QByteArray> roles = roleNames();
+ for (auto it = roles.begin(); it != roles.end(); ++it)
+ map.insert(qL1S(it.value()), data(this->index(index), it.key()));
+ return map;
+}
+
+/*!
+ \qmlmethod IntentObject IntentServer::intent(int index)
+
+ Returns the \l{IntentObject}{intent} corresponding to the given \a index in the
+ model, or \c null if the index is invalid.
+
+ \note The object ownership of the returned Intent object stays with the application-manager.
+ If you want to store this pointer, you can use the IntentServer's QAbstractListModel
+ signals or the intentAboutToBeRemoved signal to get notified if the object is about
+ to be deleted on the C++ side.
+*/
+Intent *IntentServer::intent(int index) const
{
- return convertToQml(all());
+ if (index < 0 || index >= count()) {
+ qCWarning(LogSystem) << "IntentServer::intent(index): invalid index:" << index;
+ return nullptr;
+ }
+ return m_intents.at(index);
}
-/*! \qmlmethod Intent IntentServer::find(string intentId, string applicationId, var parameters)
+/*! \qmlmethod IntentObject IntentServer::applicationIntent(string intentId, string applicationId, var parameters)
+
+ Returns the \l{IntentObject}{intent} corresponding to the given \a intentId, \a applicationId
+ and \a parameters or \c null if the id does not exist.
This method exposes the same functionality that is used internally to match incoming Intent
requests for the intent identified by \a intentId and targeted for the application identified by
\a applicationId.
Although you could iterate over the intentList yourself in JavaScript, this function has the
added benefit of also checking the optionally provided \a parameters against any given
- \l{Intent::parameterMatch}{parameter matches}.
+ \l{IntentObject::parameterMatch}{parameter matches}.
+
+ \note The object ownership of the returned Intent object stays with the application-manager.
+ If you want to store this pointer, you can use the IntentServer's QAbstractListModel
+ signals or the intentAboutToBeRemoved signal to get notified if the object is about
+ to be deleted on the C++ side.
+*/
+Intent *IntentServer::applicationIntent(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters) const
+{
+ auto it = std::find_if(m_intents.cbegin(), m_intents.cend(),
+ [intentId, applicationId, parameters](Intent *intent) -> bool {
+ return (intent->applicationId() == applicationId) && (intent->intentId() == intentId)
+ && intent->checkParameterMatch(parameters);
+ });
+ return (it != m_intents.cend()) ? *it : nullptr;
+}
+
+/*! \qmlmethod IntentObject IntentServer::packageIntent(string intentId, string packageId, var parameters)
+
+ Returns the \l{IntentObject}{intent} corresponding to the given \a intentId, \a packageId
+ and \a parameters or \c null if the id does not exist.
+
+ \sa applicationIntent
+*/
+Intent *IntentServer::packageIntent(const QString &intentId, const QString &packageId,
+ const QVariantMap &parameters) const
+{
+ auto it = std::find_if(m_intents.cbegin(), m_intents.cend(),
+ [intentId, packageId, parameters](Intent *intent) -> bool {
+ return (intent->packageId() == packageId) && (intent->intentId() == intentId)
+ && intent->checkParameterMatch(parameters);
+ });
+ return (it != m_intents.cend()) ? *it : nullptr;
+}
+
+/*! \qmlmethod IntentObject IntentServer::packageIntent(string intentId, string packageId, string applicationId, var parameters)
+
+ Returns the \l{IntentObject}{intent} corresponding to the given \a intentId, \a packageId,
+ \a applicationId and \a parameters or \c null if the id does not exist.
- If no matching Intent is found, the function will return an \l{Intent::valid}{invalid} Intent.
+ \sa applicationIntent
*/
-Intent IntentServer::find(const QString &intentId, const QString &applicationId, const QVariantMap &parameters) const
+Intent *IntentServer::packageIntent(const QString &intentId, const QString &packageId,
+ const QString &applicationId, const QVariantMap &parameters) const
{
auto it = std::find_if(m_intents.cbegin(), m_intents.cend(),
- [intentId, applicationId, parameters](const Intent &intent) -> bool {
- return (intent.applicationId() == applicationId) && (intent.intentId() == intentId)
- && intent.checkParameterMatch(parameters);
+ [intentId, packageId, applicationId, parameters](Intent *intent) -> bool {
+ return (intent->packageId() == packageId) && (intent->applicationId() == applicationId)
+ && (intent->intentId() == intentId) && intent->checkParameterMatch(parameters);
});
- return (it != m_intents.cend()) ? *it : Intent();
+ return (it != m_intents.cend()) ? *it : nullptr;
+}
+
+/*! \qmlmethod int IntentServer::indexOfIntent(string intentId, string applicationId, var parameters)
+
+ Maps the intent corresponding to the given \a intentId, \a applicationId and \a parameters to
+ its position within this model. Returns \c -1 if the specified intent is invalid.
+
+ \sa intent()
+*/
+int IntentServer::indexOfIntent(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters) const
+{
+ return m_intents.indexOf(applicationIntent(intentId, applicationId, parameters));
+}
+
+/*! \qmlmethod int IntentServer::indexOfIntent(IntentObject intent)
+
+ Maps the \a intent to its position within this model. Returns \c -1 if the specified intent is
+ invalid.
+
+ \sa intent()
+*/
+int IntentServer::indexOfIntent(Intent *intent)
+{
+ return m_intents.indexOf(intent);
}
void IntentServer::triggerRequestQueue()
@@ -333,7 +544,7 @@ void IntentServer::processRequestQueue()
if (!isSignalConnected(QMetaMethod::fromSignal(&IntentServer::disambiguationRequest))) {
// If the System-UI does not react to the signal, then just use the first match.
- isr->setHandlingApplicationId(isr->potentialIntents().first().applicationId());
+ isr->setHandlingApplicationId(isr->potentialIntents().first()->packageId());
} else {
m_disambiguationQueue.enqueue(isr);
isr->setState(IntentServerRequest::State::WaitingForDisambiguation);
@@ -413,12 +624,23 @@ void IntentServer::processRequestQueue()
triggerRequestQueue();
}
-IntentList IntentServer::convertToQml(const QVector<Intent> &intents)
+QList<QObject *> IntentServer::convertToQml(const QVector<Intent *> &intents)
{
- QVariantList vl;
+ QList<QObject *> ol;
for (auto intent : intents)
- vl << QVariant::fromValue(intent);
- return vl;
+ ol << intent;
+ return ol;
+}
+
+QString IntentServer::packageIdForApplicationId(const QString &applicationId) const
+{
+ for (auto pit = m_knownApplications.cbegin(); pit != m_knownApplications.cend(); ++pit) {
+ for (auto ait = pit.value().cbegin(); ait != pit.value().cend(); ++ait) {
+ if (*ait == applicationId)
+ return pit.key();
+ }
+ }
+ return QString();
}
/*!
@@ -449,7 +671,7 @@ IntentList IntentServer::convertToQml(const QVector<Intent> &intents)
\sa IntentClient::sendIntentRequest
*/
-void IntentServer::acknowledgeDisambiguationRequest(const QUuid &requestId, const Intent &selectedIntent)
+void IntentServer::acknowledgeDisambiguationRequest(const QUuid &requestId, Intent *selectedIntent)
{
internalDisambiguateRequest(requestId, false, selectedIntent);
}
@@ -464,10 +686,10 @@ void IntentServer::acknowledgeDisambiguationRequest(const QUuid &requestId, cons
*/
void IntentServer::rejectDisambiguationRequest(const QUuid &requestId)
{
- internalDisambiguateRequest(requestId, true, Intent());
+ internalDisambiguateRequest(requestId, true, nullptr);
}
-void IntentServer::internalDisambiguateRequest(const QUuid &requestId, bool reject, const Intent &selectedIntent)
+void IntentServer::internalDisambiguateRequest(const QUuid &requestId, bool reject, Intent *selectedIntent)
{
IntentServerRequest *isr = nullptr;
for (int i = 0; i < m_disambiguationQueue.size(); ++i) {
@@ -478,17 +700,17 @@ void IntentServer::internalDisambiguateRequest(const QUuid &requestId, bool reje
}
if (!isr) {
- qmlWarning(this) << "Got a disambiguation acknowledge or reject for intent" << requestId
- << "but no disambiguation was expected for this intent";
+ qmlWarning(this) << "Got a disambiguation acknowledge or reject for intent " << requestId
+ << ", but no disambiguation was expected for this intent";
} else {
if (reject) {
isr->setRequestFailed(qSL("Disambiguation was rejected"));
} else if (isr->potentialIntents().contains(selectedIntent)) {
- isr->setHandlingApplicationId(selectedIntent.applicationId());
+ isr->setHandlingApplicationId(selectedIntent->packageId());
isr->setState(IntentServerRequest::State::Disambiguated);
} else {
qCWarning(LogIntents) << "IntentServer::acknowledgeDisambiguationRequest for intent"
- << requestId << "tried to disambiguate to the intent" << selectedIntent.intentId()
+ << requestId << "tried to disambiguate to the intent" << selectedIntent->intentId()
<< "which was not in the list of potential disambiguations";
isr->setRequestFailed(qSL("Failed to disambiguate"));
@@ -570,11 +792,13 @@ IntentServerRequest *IntentServer::requestToSystem(const QString &requestingAppl
return nullptr;
}
- QVector<Intent> intents;
- if (applicationId.isEmpty())
- intents = filterByIntentId(all(), intentId, parameters);
- else if (Intent intent = find(intentId, applicationId, parameters))
- intents << intent;
+ QVector<Intent *> intents;
+ if (applicationId.isEmpty()) {
+ intents = filterByIntentId(m_intents, intentId, parameters);
+ } else {
+ if (Intent *intent = this->applicationIntent(intentId, applicationId, parameters))
+ intents << intent;
+ }
if (intents.isEmpty()) {
qCWarning(LogIntents) << "Unknown intent" << intentId << "was requested from application"
diff --git a/src/intent-server-lib/intentserver.h b/src/intent-server-lib/intentserver.h
index 1bf62ade..6bd16228 100644
--- a/src/intent-server-lib/intentserver.h
+++ b/src/intent-server-lib/intentserver.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -42,7 +43,7 @@
#pragma once
-#include <QObject>
+#include <QAbstractListModel>
#include <QVariantMap>
#include <QVector>
#include <QUuid>
@@ -57,16 +58,13 @@ class AbstractRuntime;
class IntentServerRequest;
class IntentServerSystemInterface;
-// We cannot expose a list of Q_GADGETs to QML in a type-safe way. We can however
-// at least try to make the C++ side of the API a bit more descriptive.
-typedef QVariantList IntentList;
-class IntentServer : public QObject
+class IntentServer : public QAbstractListModel
{
Q_OBJECT
Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/IntentServer 2.0 SINGLETON")
- Q_PROPERTY(IntentList intentList READ intentList NOTIFY intentListChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
public:
~IntentServer() override;
@@ -77,51 +75,63 @@ public:
void setStartApplicationTimeout(int timeout);
void setReplyFromApplicationTimeout(int timeout);
- bool addApplication(const QString &applicationId);
- void removeApplication(const QString &applicationId);
+ bool addPackage(const QString &packageId);
+ void removePackage(const QString &packageId);
- bool addApplicationBackgroundHandler(const QString &applicationId, const QString &backgroundServiceId);
- void removeApplicationBackgroundHandler(const QString &applicationId, const QString &backgroundServiceId);
+ bool addApplication(const QString &applicationId, const QString &packageId);
+ void removeApplication(const QString &applicationId, const QString &packageId);
- Intent addIntent(const QString &id, const QString &applicationId, const QStringList &capabilities,
- Intent::Visibility visibility, const QVariantMap &parameterMatch = QVariantMap());
+ Intent *addIntent(const QString &id, const QString &packageId, const QString &handlingApplicationId,
+ const QStringList &capabilities, Intent::Visibility visibility,
+ const QVariantMap &parameterMatch, const QMap<QString, QString> &names,
+ const QUrl &icon, const QStringList &categories);
- Intent addIntent(const QString &id, const QString &applicationId, const QString &backgroundHandlerId,
- const QStringList &capabilities, Intent::Visibility visibility,
- const QVariantMap &parameterMatch = QVariantMap());
+ void removeIntent(Intent *intent);
- void removeIntent(const Intent &intent);
+ QVector<Intent *> filterByIntentId(const QVector<Intent *> &intents, const QString &intentId,
+ const QVariantMap &parameters = QVariantMap{}) const;
+ QVector<Intent *> filterByRequestingApplicationId(const QVector<Intent *> &intents,
+ const QString &requestingApplicationId) const;
- QVector<Intent> all() const;
- QVector<Intent> filterByIntentId(const QVector<Intent> &intents, const QString &intentId,
- const QVariantMap &parameters = QVariantMap{}) const;
- QVector<Intent> filterByHandlingApplicationId(const QVector<Intent> &intents,
- const QString &handlingApplicationId,
- const QVariantMap &parameters = QVariantMap{}) const;
- QVector<Intent> filterByRequestingApplicationId(const QVector<Intent> &intents,
- const QString &requestingApplicationId) const;
+ // the item model part
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ QHash<int, QByteArray> roleNames() const override;
// vvv QML API vvv
- IntentList intentList() const;
-
- Q_INVOKABLE Intent find(const QString &intentId, const QString &applicationId,
- const QVariantMap &parameters = QVariantMap{}) const;
-
- Q_INVOKABLE void acknowledgeDisambiguationRequest(const QUuid &requestId, const Intent &selectedIntent);
+ int count() const;
+
+ Q_INVOKABLE QVariantMap get(int index) const;
+ Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(Intent) *intent(int index) const;
+ Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(Intent) *applicationIntent(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters = QVariantMap{}) const;
+ Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(Intent) *packageIntent(const QString &intentId, const QString &packageId,
+ const QVariantMap &parameters = QVariantMap{}) const;
+ Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(Intent) *packageIntent(const QString &intentId, const QString &packageId,
+ const QString &applicationId,
+ const QVariantMap &parameters = QVariantMap{}) const;
+ Q_INVOKABLE int indexOfIntent(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters = QVariantMap{}) const;
+ Q_INVOKABLE int indexOfIntent(Intent *intent);
+
+ Q_INVOKABLE void acknowledgeDisambiguationRequest(const QUuid &requestId, Intent *selectedIntent);
Q_INVOKABLE void rejectDisambiguationRequest(const QUuid &requestId);
signals:
- void intentAdded(const Intent &intent);
- void intentRemoved(const Intent &intent);
- void intentListChanged();
+ void intentAdded(QT_PREPEND_NAMESPACE_AM(Intent) *intent);
+ void intentAboutToBeRemoved(QT_PREPEND_NAMESPACE_AM(Intent) *intent);
- void disambiguationRequest(const QUuid &requestId, const IntentList &potentialIntents,
+ void countChanged();
+
+ // QML can only accept QList<QObject *> as signal parameter. Using QList<Intent *> or
+ // QVector<QObject> will lead to an undefined QVariant on the QML side.
+ void disambiguationRequest(const QUuid &requestId, const QList<QObject *> &potentialIntents,
const QVariantMap &parameters);
/// ^^^ QML API ^^^
private:
- void internalDisambiguateRequest(const QUuid &requestId, bool reject, const Intent &selectedIntent);
+ void internalDisambiguateRequest(const QUuid &requestId, bool reject, Intent *selectedIntent);
void applicationWasStarted(const QString &applicationId);
void replyFromApplication(const QString &replyingApplicationId, const QUuid &requestId,
bool error, const QVariantMap &result);
@@ -132,15 +142,17 @@ private:
void enqueueRequest(IntentServerRequest *isr);
void processRequestQueue();
- static IntentList convertToQml(const QVector<Intent> &intents);
+ static QList<QObject *> convertToQml(const QVector<Intent *> &intents);
+ QString packageIdForApplicationId(const QString &applicationId) const;
private:
IntentServer(IntentServerSystemInterface *systemInterface, QObject *parent = nullptr);
Q_DISABLE_COPY(IntentServer)
static IntentServer *s_instance;
- QStringList m_knownApplications;
- QMap<QString, QStringList> m_knownBackgroundServices;
+ static QHash<int, QByteArray> s_roleNames;
+
+ QMap<QString, QStringList> m_knownApplications;
QQueue<IntentServerRequest *> m_requestQueue;
@@ -148,11 +160,12 @@ private:
QQueue<IntentServerRequest *> m_startingAppQueue;
QQueue<IntentServerRequest *> m_sentToAppQueue;
- int m_disambiguationTimeout = 10000;
- int m_startingAppTimeout = 3000;
- int m_sentToAppTimeout = 5000;
+ // no timeouts by default -- these have to be set at runtime
+ int m_disambiguationTimeout = 0;
+ int m_startingAppTimeout = 0;
+ int m_sentToAppTimeout = 0;
- QVector<Intent> m_intents;
+ QVector<Intent *> m_intents;
IntentServerSystemInterface *m_systemInterface;
friend class IntentServerSystemInterface;
diff --git a/src/intent-server-lib/intentserverrequest.cpp b/src/intent-server-lib/intentserverrequest.cpp
index 52fd8280..059d20e8 100644
--- a/src/intent-server-lib/intentserverrequest.cpp
+++ b/src/intent-server-lib/intentserverrequest.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -45,7 +46,7 @@
QT_BEGIN_NAMESPACE_AM
IntentServerRequest::IntentServerRequest(const QString &requestingApplicationId, const QString &intentId,
- const QVector<Intent> &potentialIntents,
+ const QVector<Intent *> &potentialIntents,
const QVariantMap &parameters)
: m_id(QUuid::createUuid())
, m_state(State::ReceivedRequest)
@@ -57,7 +58,7 @@ IntentServerRequest::IntentServerRequest(const QString &requestingApplicationId,
Q_ASSERT(!potentialIntents.isEmpty());
if (potentialIntents.size() == 1)
- setHandlingApplicationId(potentialIntents.first().applicationId());
+ setHandlingApplicationId(potentialIntents.first()->applicationId());
}
IntentServerRequest::State IntentServerRequest::state() const
@@ -85,7 +86,7 @@ QString IntentServerRequest::handlingApplicationId() const
return m_handlingApplicationId;
}
-QVector<Intent> IntentServerRequest::potentialIntents() const
+QVector<Intent *> IntentServerRequest::potentialIntents() const
{
return m_potentialIntents;
}
diff --git a/src/intent-server-lib/intentserverrequest.h b/src/intent-server-lib/intentserverrequest.h
index 1d3b2980..78904c52 100644
--- a/src/intent-server-lib/intentserverrequest.h
+++ b/src/intent-server-lib/intentserverrequest.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -60,7 +61,7 @@ class IntentServerRequest
public:
IntentServerRequest(const QString &requestingApplicationId, const QString &intentId,
- const QVector<Intent> &potentialIntents, const QVariantMap &parameters);
+ const QVector<Intent *> &potentialIntents, const QVariantMap &parameters);
enum class State {
ReceivedRequest,
@@ -79,7 +80,7 @@ public:
QString intentId() const;
QString requestingApplicationId() const;
QString handlingApplicationId() const;
- QVector<Intent> potentialIntents() const;
+ QVector<Intent *> potentialIntents() const;
QVariantMap parameters() const;
bool succeeded() const;
QVariantMap result() const;
@@ -97,7 +98,7 @@ private:
QString m_intentId;
QString m_requestingApplicationId;
QString m_handlingApplicationId;
- QVector<Intent> m_potentialIntents;
+ QVector<Intent *> m_potentialIntents;
QVariantMap m_parameters;
QVariantMap m_result;
};
diff --git a/src/intent-server-lib/intentserversysteminterface.cpp b/src/intent-server-lib/intentserversysteminterface.cpp
index 84e54b02..f6552c02 100644
--- a/src/intent-server-lib/intentserversysteminterface.cpp
+++ b/src/intent-server-lib/intentserversysteminterface.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -60,7 +61,10 @@ IntentServer *IntentServerSystemInterface::intentServer() const
return m_is;
}
-IntentServerRequest *IntentServerSystemInterface::requestToSystem(const QString &requestingApplicationId, const QString &intentId, const QString &applicationId, const QVariantMap &parameters)
+IntentServerRequest *IntentServerSystemInterface::requestToSystem(const QString &requestingApplicationId,
+ const QString &intentId,
+ const QString &applicationId,
+ const QVariantMap &parameters)
{
// not possible to do via signal, due to return value
return m_is->requestToSystem(requestingApplicationId, intentId, applicationId, parameters);
diff --git a/src/intent-server-lib/intentserversysteminterface.h b/src/intent-server-lib/intentserversysteminterface.h
index 3e03806b..1a2d22e5 100644
--- a/src/intent-server-lib/intentserversysteminterface.h
+++ b/src/intent-server-lib/intentserversysteminterface.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/launcher-lib/applicationmanagerwindow.cpp b/src/launcher-lib/applicationmanagerwindow.cpp
index 766f4cbe..5bb1e645 100644
--- a/src/launcher-lib/applicationmanagerwindow.cpp
+++ b/src/launcher-lib/applicationmanagerwindow.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/launcher-lib/applicationmanagerwindow_p.h b/src/launcher-lib/applicationmanagerwindow_p.h
index 6a4ff5f1..825f44cb 100644
--- a/src/launcher-lib/applicationmanagerwindow_p.h
+++ b/src/launcher-lib/applicationmanagerwindow_p.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/launcher-lib/qmlapplicationinterface.cpp b/src/launcher-lib/dbusapplicationinterface.cpp
index 07c914f1..ab505f81 100644
--- a/src/launcher-lib/qmlapplicationinterface.cpp
+++ b/src/launcher-lib/dbusapplicationinterface.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -51,9 +51,9 @@
#include <QThread>
#include "global.h"
-#include "qmlapplicationinterface.h"
-#include "qmlapplicationinterfaceextension.h"
-#include "qmlnotification.h"
+#include "dbusapplicationinterface.h"
+#include "dbusapplicationinterfaceextension.h"
+#include "dbusnotification.h"
#include "notification.h"
#include "ipcwrapperobject.h"
#include "utilities.h"
@@ -63,19 +63,20 @@
QT_BEGIN_NAMESPACE_AM
-QmlApplicationInterface *QmlApplicationInterface::s_instance = nullptr;
+DBusApplicationInterface *DBusApplicationInterface::s_instance = nullptr;
-QmlApplicationInterface::QmlApplicationInterface(const QString &dbusConnectionName, const QString &dbusNotificationBusName, QObject *parent)
+DBusApplicationInterface::DBusApplicationInterface(const QString &dbusConnectionName,
+ const QString &dbusNotificationBusName, QObject *parent)
: ApplicationInterface(parent)
, m_connection(dbusConnectionName)
, m_notificationConnection(dbusNotificationBusName)
{
- if (QmlApplicationInterface::s_instance)
- qCritical("ERROR: only one instance of QmlApplicationInterface is allowed");
+ if (DBusApplicationInterface::s_instance)
+ qCritical("ERROR: only one instance of DBusApplicationInterface is allowed");
s_instance = this;
}
-bool QmlApplicationInterface::initialize()
+bool DBusApplicationInterface::initialize(bool hasRuntime)
{
// we are working with very small delays in the milli-second range here, so a linear factor
// to support valgrind would have to be very large and probably conflict with usage elsewhere
@@ -94,36 +95,43 @@ bool QmlApplicationInterface::initialize()
return nullptr;
};
- m_runtimeIf = tryConnect(qSL(""), qSL("/RuntimeInterface"), qSL("io.qt.ApplicationManager.RuntimeInterface"),
- m_connection, this);
- m_applicationIf = tryConnect(qSL(""), qSL("/ApplicationInterface"), qSL("io.qt.ApplicationManager.ApplicationInterface"),
- m_connection, this);
+ m_applicationIf = tryConnect(qSL(""), qSL("/ApplicationInterface"),
+ qSL("io.qt.ApplicationManager.ApplicationInterface"), m_connection, this);
if (!m_applicationIf) {
qCritical("ERROR: could not connect to the ApplicationInterface on the P2P D-Bus");
return false;
}
- if (!m_runtimeIf) {
- qCritical("ERROR: could not connect to the RuntimeInterface on the P2P D-Bus");
- return false;
- }
+
if (!m_applicationIf->isValid()) {
qCritical("ERROR: ApplicationInterface on the P2P D-Bus is not valid: %s",
qPrintable(m_applicationIf->lastError().message()));
return false;
}
- if (!m_runtimeIf->isValid()) {
- qCritical("ERROR: RuntimeInterface on the P2P D-Bus is not valid: %s",
- qPrintable(m_runtimeIf->lastError().message()));
- return false;
- }
bool ok = true;
- ok = ok && connect(m_runtimeIf, SIGNAL(startApplication(QString,QString,QString,QString,QVariantMap,QVariantMap)),
- this, SIGNAL(startApplication(QString,QString,QString,QString,QVariantMap,QVariantMap)));
- if (!ok)
- qCritical("ERROR: could not connect the RuntimeInterface via D-Bus: %s", qPrintable(m_runtimeIf->lastError().name()));
+ if (hasRuntime) {
+ m_runtimeIf = tryConnect(qSL(""), qSL("/RuntimeInterface"), qSL("io.qt.ApplicationManager.RuntimeInterface"),
+ m_connection, this);
+ if (!m_runtimeIf) {
+ qCritical("ERROR: could not connect to the RuntimeInterface on the P2P D-Bus");
+ return false;
+ }
+
+ if (!m_runtimeIf->isValid()) {
+ qCritical("ERROR: RuntimeInterface on the P2P D-Bus is not valid: %s",
+ qPrintable(m_runtimeIf->lastError().message()));
+ return false;
+ }
+
+ ok = connect(m_runtimeIf, SIGNAL(startApplication(QString,QString,QString,QString,QVariantMap,QVariantMap)),
+ this, SIGNAL(startApplication(QString,QString,QString,QString,QVariantMap,QVariantMap)));
+ if (!ok) {
+ qCritical("ERROR: could not connect the RuntimeInterface via D-Bus: %s",
+ qPrintable(m_runtimeIf->lastError().name()));
+ }
+ }
ok = ok && connect(m_applicationIf, SIGNAL(quit()), this, SIGNAL(quit()));
ok = ok && connect(m_applicationIf, SIGNAL(memoryLowWarning()), this, SIGNAL(memoryLowWarning()));
@@ -151,7 +159,7 @@ bool QmlApplicationInterface::initialize()
}
}
- QmlApplicationInterfaceExtension::initialize(m_connection);
+ DBusApplicationInterfaceExtension::initialize(m_connection);
auto intentClientDBusInterface = new IntentClientDBusImplementation(m_connection.name());
if (!IntentClient::createInstance(intentClientDBusInterface)) {
@@ -164,56 +172,56 @@ bool QmlApplicationInterface::initialize()
return ok;
}
-QString QmlApplicationInterface::applicationId() const
+QString DBusApplicationInterface::applicationId() const
{
if (m_appId.isEmpty() && m_applicationIf->isValid())
m_appId = m_applicationIf->property("applicationId").toString();
return m_appId;
}
-QVariantMap QmlApplicationInterface::name() const
+QVariantMap DBusApplicationInterface::name() const
{
return m_name;
}
-QUrl QmlApplicationInterface::icon() const
+QUrl DBusApplicationInterface::icon() const
{
return QUrl::fromLocalFile(m_icon);
}
-QString QmlApplicationInterface::version() const
+QString DBusApplicationInterface::version() const
{
return m_version;
}
-Notification *QmlApplicationInterface::createNotification()
+Notification *DBusApplicationInterface::createNotification()
{
- QmlNotification *n = new QmlNotification(this, Notification::Dynamic);
+ DBusNotification *n = new DBusNotification(this, Notification::Dynamic);
return n;
}
-void QmlApplicationInterface::acknowledgeQuit() const
+void DBusApplicationInterface::acknowledgeQuit() const
{
QCoreApplication::instance()->quit();
}
-void QmlApplicationInterface::finishedInitialization()
+void DBusApplicationInterface::finishedInitialization()
{
if (m_applicationIf->isValid())
m_applicationIf->asyncCall(qSL("finishedInitialization"));
}
-QVariantMap QmlApplicationInterface::systemProperties() const
+QVariantMap DBusApplicationInterface::systemProperties() const
{
return m_systemProperties;
}
-QVariantMap QmlApplicationInterface::applicationProperties() const
+QVariantMap DBusApplicationInterface::applicationProperties() const
{
return m_applicationProperties;
}
-uint QmlApplicationInterface::notificationShow(QmlNotification *n)
+uint DBusApplicationInterface::notificationShow(DBusNotification *n)
{
if (n && m_notifyIf && m_notifyIf->isValid()) {
QDBusReply<uint> newId = m_notifyIf->call(qSL("Notify"), applicationId(), n->notificationId(),
@@ -229,16 +237,16 @@ uint QmlApplicationInterface::notificationShow(QmlNotification *n)
}
-void QmlApplicationInterface::notificationClose(QmlNotification *n)
+void DBusApplicationInterface::notificationClose(DBusNotification *n)
{
if (n && m_notifyIf && m_notifyIf->isValid())
m_notifyIf->asyncCall(qSL("CloseNotification"), n->notificationId());
}
-void QmlApplicationInterface::notificationClosed(uint notificationId, uint reason)
+void DBusApplicationInterface::notificationClosed(uint notificationId, uint reason)
{
qDebug("Notification was closed signal: %u", notificationId);
- for (const QPointer<QmlNotification> &n : m_allNotifications) {
+ for (const QPointer<DBusNotification> &n : m_allNotifications) {
if (n->notificationId() == notificationId) {
n->libnotifyNotificationClosed(reason);
m_allNotifications.removeAll(n);
@@ -247,10 +255,10 @@ void QmlApplicationInterface::notificationClosed(uint notificationId, uint reaso
}
}
-void QmlApplicationInterface::notificationActionTriggered(uint notificationId, const QString &actionId)
+void DBusApplicationInterface::notificationActionTriggered(uint notificationId, const QString &actionId)
{
qDebug("Notification action triggered signal: %u %s", notificationId, qPrintable(actionId));
- for (const QPointer<QmlNotification> &n : m_allNotifications) {
+ for (const QPointer<DBusNotification> &n : m_allNotifications) {
if (n->notificationId() == notificationId) {
n->libnotifyActionInvoked(actionId);
break;
diff --git a/src/launcher-lib/qmlapplicationinterface.h b/src/launcher-lib/dbusapplicationinterface.h
index 467c3069..ed70058d 100644
--- a/src/launcher-lib/qmlapplicationinterface.h
+++ b/src/launcher-lib/dbusapplicationinterface.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -54,22 +54,22 @@ QT_FORWARD_DECLARE_CLASS(QDBusInterface)
QT_BEGIN_NAMESPACE_AM
-class QmlNotification;
+class DBusNotification;
class Notification;
class IntentClientRequest;
class Controller;
-class QmlApplicationInterfaceExtension;
+class DBusApplicationInterfaceExtension;
-class QmlApplicationInterface : public ApplicationInterface
+class DBusApplicationInterface : public ApplicationInterface
{
Q_OBJECT
Q_CLASSINFO("AM-QmlType", "QtApplicationManager.Application/ApplicationInterface 2.0 UNCREATABLE")
public:
- explicit QmlApplicationInterface(const QString &dbusConnectionName,
+ explicit DBusApplicationInterface(const QString &dbusConnectionName,
const QString &dbusNotificationBusName, QObject *parent = nullptr);
- bool initialize();
+ bool initialize(bool hasRuntime = false);
QString applicationId() const override;
QVariantMap name() const override;
@@ -89,8 +89,8 @@ private:
const QString &mimeType, const QVariantMap &runtimeParams,
const QVariantMap systemProperties);
- uint notificationShow(QmlNotification *n);
- void notificationClose(QmlNotification *n);
+ uint notificationShow(DBusNotification *n);
+ void notificationClose(DBusNotification *n);
QDBusConnection m_connection;
QDBusConnection m_notificationConnection;
@@ -103,13 +103,13 @@ private:
QString m_version;
QVariantMap m_systemProperties;
QVariantMap m_applicationProperties;
- QVector<QPointer<QmlNotification> > m_allNotifications;
+ QVector<QPointer<DBusNotification> > m_allNotifications;
- static QmlApplicationInterface *s_instance;
+ static DBusApplicationInterface *s_instance;
- friend class QmlNotification;
+ friend class DBusNotification;
friend class Controller;
- friend class QmlApplicationInterfaceExtension;
+ friend class DBusApplicationInterfaceExtension;
};
QT_END_NAMESPACE_AM
diff --git a/src/launcher-lib/qmlapplicationinterfaceextension.cpp b/src/launcher-lib/dbusapplicationinterfaceextension.cpp
index 97ee48d6..080156ba 100644
--- a/src/launcher-lib/qmlapplicationinterfaceextension.cpp
+++ b/src/launcher-lib/dbusapplicationinterfaceextension.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -43,16 +43,16 @@
#include <QDBusInterface>
#include "logging.h"
-#include "qmlapplicationinterfaceextension.h"
-#include "qmlapplicationinterface.h"
+#include "dbusapplicationinterfaceextension.h"
+#include "dbusapplicationinterface.h"
#include "ipcwrapperobject.h"
QT_BEGIN_NAMESPACE_AM
-class QmlApplicationInterfaceExtensionPrivate
+class DBusApplicationInterfaceExtensionPrivate
{
public:
- QmlApplicationInterfaceExtensionPrivate(const QDBusConnection &connection)
+ DBusApplicationInterfaceExtensionPrivate(const QDBusConnection &connection)
: m_connection(connection)
{ }
@@ -60,58 +60,58 @@ public:
QDBusConnection m_connection;
};
-QmlApplicationInterfaceExtensionPrivate *QmlApplicationInterfaceExtension::d = nullptr;
+DBusApplicationInterfaceExtensionPrivate *DBusApplicationInterfaceExtension::d = nullptr;
-void QmlApplicationInterfaceExtension::initialize(const QDBusConnection &connection)
+void DBusApplicationInterfaceExtension::initialize(const QDBusConnection &connection)
{
if (!d)
- d = new QmlApplicationInterfaceExtensionPrivate(connection);
+ d = new DBusApplicationInterfaceExtensionPrivate(connection);
}
-QmlApplicationInterfaceExtension::QmlApplicationInterfaceExtension(QObject *parent)
+DBusApplicationInterfaceExtension::DBusApplicationInterfaceExtension(QObject *parent)
: QObject(parent)
{
Q_ASSERT(d);
- if (QmlApplicationInterface::s_instance->m_applicationIf) {
- connect(QmlApplicationInterface::s_instance->m_applicationIf, SIGNAL(interfaceCreated(QString)),
+ if (DBusApplicationInterface::s_instance->m_applicationIf) {
+ connect(DBusApplicationInterface::s_instance->m_applicationIf, SIGNAL(interfaceCreated(QString)),
this, SLOT(onInterfaceCreated(QString)));
} else {
qCritical("ERROR: ApplicationInterface not initialized!");
}
}
-QmlApplicationInterfaceExtension::~QmlApplicationInterfaceExtension()
+DBusApplicationInterfaceExtension::~DBusApplicationInterfaceExtension()
{
d->m_interfaces.remove(m_name);
}
-QString QmlApplicationInterfaceExtension::name() const
+QString DBusApplicationInterfaceExtension::name() const
{
return m_name;
}
-bool QmlApplicationInterfaceExtension::isReady() const
+bool DBusApplicationInterfaceExtension::isReady() const
{
return m_object;
}
-QObject *QmlApplicationInterfaceExtension::object() const
+QObject *DBusApplicationInterfaceExtension::object() const
{
return m_object;
}
-void QmlApplicationInterfaceExtension::classBegin()
+void DBusApplicationInterfaceExtension::classBegin()
{
}
-void QmlApplicationInterfaceExtension::componentComplete()
+void DBusApplicationInterfaceExtension::componentComplete()
{
tryInit();
}
-void QmlApplicationInterfaceExtension::tryInit()
+void DBusApplicationInterfaceExtension::tryInit()
{
if (m_name.isEmpty())
return;
@@ -154,7 +154,7 @@ void QmlApplicationInterfaceExtension::tryInit()
emit readyChanged();
}
-void QmlApplicationInterfaceExtension::setName(const QString &name)
+void DBusApplicationInterfaceExtension::setName(const QString &name)
{
if (!m_complete) {
m_name = name;
@@ -164,7 +164,7 @@ void QmlApplicationInterfaceExtension::setName(const QString &name)
}
}
-void QmlApplicationInterfaceExtension::onInterfaceCreated(const QString &interfaceName)
+void DBusApplicationInterfaceExtension::onInterfaceCreated(const QString &interfaceName)
{
if (m_name == interfaceName)
tryInit();
diff --git a/src/launcher-lib/qmlapplicationinterfaceextension.h b/src/launcher-lib/dbusapplicationinterfaceextension.h
index 250c7b85..0e18fa79 100644
--- a/src/launcher-lib/qmlapplicationinterfaceextension.h
+++ b/src/launcher-lib/dbusapplicationinterfaceextension.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -50,9 +50,9 @@ QT_FORWARD_DECLARE_CLASS(QDBusConnection)
QT_BEGIN_NAMESPACE_AM
-class QmlApplicationInterfaceExtensionPrivate;
+class DBusApplicationInterfaceExtensionPrivate;
-class QmlApplicationInterfaceExtension : public QObject, public QQmlParserStatus
+class DBusApplicationInterfaceExtension : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/ApplicationInterfaceExtension 2.0")
@@ -65,8 +65,8 @@ class QmlApplicationInterfaceExtension : public QObject, public QQmlParserStatus
public:
static void initialize(const QDBusConnection &connection);
- explicit QmlApplicationInterfaceExtension(QObject *parent = nullptr);
- ~QmlApplicationInterfaceExtension() override;
+ explicit DBusApplicationInterfaceExtension(QObject *parent = nullptr);
+ ~DBusApplicationInterfaceExtension() override;
QString name() const;
bool isReady() const;
@@ -89,7 +89,7 @@ signals:
private:
void tryInit();
- static QmlApplicationInterfaceExtensionPrivate *d;
+ static DBusApplicationInterfaceExtensionPrivate *d;
QString m_name;
QObject *m_object = nullptr;
bool m_complete = false;
diff --git a/src/launcher-lib/qmlnotification.cpp b/src/launcher-lib/dbusnotification.cpp
index a3de76f1..2042c765 100644
--- a/src/launcher-lib/qmlnotification.cpp
+++ b/src/launcher-lib/dbusnotification.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -40,25 +40,30 @@
**
****************************************************************************/
-#include "qmlnotification.h"
-#include "qmlapplicationinterface.h"
+#include "dbusnotification.h"
+#include "dbusapplicationinterface.h"
QT_BEGIN_NAMESPACE_AM
-QmlNotification::QmlNotification(QObject *parent, ConstructionMode mode)
+DBusNotification::DBusNotification(QObject *parent, ConstructionMode mode)
: Notification(parent, mode)
{ }
-void QmlNotification::libnotifyClose()
+DBusNotification *DBusNotification::create(QObject *parent)
{
- if (QmlApplicationInterface::s_instance)
- QmlApplicationInterface::s_instance->notificationClose(this);
+ return new DBusNotification(parent, QtAM::Notification::Dynamic);
}
-uint QmlNotification::libnotifyShow()
+void DBusNotification::libnotifyClose()
{
- if (QmlApplicationInterface::s_instance)
- return QmlApplicationInterface::s_instance->notificationShow(this);
+ if (DBusApplicationInterface::s_instance)
+ DBusApplicationInterface::s_instance->notificationClose(this);
+}
+
+uint DBusNotification::libnotifyShow()
+{
+ if (DBusApplicationInterface::s_instance)
+ return DBusApplicationInterface::s_instance->notificationShow(this);
return 0;
}
diff --git a/src/launcher-lib/qmlnotification.h b/src/launcher-lib/dbusnotification.h
index b0c8826d..18d03d39 100644
--- a/src/launcher-lib/qmlnotification.h
+++ b/src/launcher-lib/dbusnotification.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -47,18 +47,20 @@
QT_BEGIN_NAMESPACE_AM
-class QmlApplicationInterface;
+class DBusApplicationInterface;
-class QmlNotification : public Notification // clazy:exclude=missing-qobject-macro
+class DBusNotification : public Notification // clazy:exclude=missing-qobject-macro
{
public:
- QmlNotification(QObject *parent = nullptr, Notification::ConstructionMode mode = Notification::Declarative);
+ DBusNotification(QObject *parent = nullptr, Notification::ConstructionMode mode = Notification::Declarative);
+
+ static DBusNotification *create(QObject *parent = nullptr);
protected:
uint libnotifyShow() override;
void libnotifyClose() override;
- friend class QmlApplicationInterface;
+ friend class DBusApplicationInterface;
};
QT_END_NAMESPACE_AM
diff --git a/src/launcher-lib/intentclientdbusimplementation.cpp b/src/launcher-lib/intentclientdbusimplementation.cpp
index 9b5b2a6f..5da608a6 100644
--- a/src/launcher-lib/intentclientdbusimplementation.cpp
+++ b/src/launcher-lib/intentclientdbusimplementation.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/launcher-lib/intentclientdbusimplementation.h b/src/launcher-lib/intentclientdbusimplementation.h
index 096634d2..06be71f2 100644
--- a/src/launcher-lib/intentclientdbusimplementation.h
+++ b/src/launcher-lib/intentclientdbusimplementation.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/launcher-lib/ipcwrapperobject.cpp b/src/launcher-lib/ipcwrapperobject.cpp
index 1a9bc0e6..0d3035f2 100644
--- a/src/launcher-lib/ipcwrapperobject.cpp
+++ b/src/launcher-lib/ipcwrapperobject.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/launcher-lib/ipcwrapperobject.h b/src/launcher-lib/ipcwrapperobject.h
index e7175faf..b36b4ed1 100644
--- a/src/launcher-lib/ipcwrapperobject.h
+++ b/src/launcher-lib/ipcwrapperobject.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/launcher-lib/ipcwrapperobject_p.h b/src/launcher-lib/ipcwrapperobject_p.h
index 95d3e3b8..9d980d75 100644
--- a/src/launcher-lib/ipcwrapperobject_p.h
+++ b/src/launcher-lib/ipcwrapperobject_p.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/launcher-lib/launcher-lib.pro b/src/launcher-lib/launcher-lib.pro
index df00d155..80c70d53 100644
--- a/src/launcher-lib/launcher-lib.pro
+++ b/src/launcher-lib/launcher-lib.pro
@@ -20,10 +20,10 @@ CONFIG -= create_cmake
DBUS_INTERFACES += ../dbus-lib/io.qt.applicationmanager.intentinterface.xml
SOURCES += \
- qmlapplicationinterface.cpp \
+ dbusapplicationinterface.cpp \
ipcwrapperobject.cpp \
- qmlapplicationinterfaceextension.cpp \
- qmlnotification.cpp \
+ dbusapplicationinterfaceextension.cpp \
+ dbusnotification.cpp \
launchermain.cpp \
intentclientdbusimplementation.cpp
@@ -40,11 +40,11 @@ SOURCES += \
}
HEADERS += \
- qmlapplicationinterface.h \
+ dbusapplicationinterface.h \
ipcwrapperobject.h \
ipcwrapperobject_p.h \
- qmlapplicationinterfaceextension.h \
- qmlnotification.h \
+ dbusapplicationinterfaceextension.h \
+ dbusnotification.h \
launchermain.h \
intentclientdbusimplementation.h
diff --git a/src/launcher-lib/launchermain.cpp b/src/launcher-lib/launchermain.cpp
index 5b573c4e..a5417916 100644
--- a/src/launcher-lib/launchermain.cpp
+++ b/src/launcher-lib/launchermain.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -58,17 +59,21 @@
QT_BEGIN_NAMESPACE_AM
-LauncherMain::LauncherMain(int &argc, char **argv) Q_DECL_NOEXCEPT
- : LauncherMainBase(SharedMain::preConstructor(argc), argv)
- , SharedMain()
-{ }
+LauncherMain *LauncherMain::s_instance = nullptr;
+
+LauncherMain::LauncherMain() Q_DECL_NOEXCEPT
+{
+ if (LauncherMain::s_instance)
+ qCritical("ERROR: only one instance of LauncherMain is allowed");
+ s_instance = this;
+};
LauncherMain::~LauncherMain()
{ }
LauncherMain *LauncherMain::instance()
{
- return qobject_cast<LauncherMain *>(qApp);
+ return s_instance;
}
void LauncherMain::registerWaylandExtensions() Q_DECL_NOEXCEPT
@@ -193,10 +198,15 @@ void LauncherMain::setApplicationId(const QString &applicationId)
void LauncherMain::loadConfiguration(const QByteArray &configYaml) Q_DECL_NOEXCEPT_EXPR(false)
{
- auto docs = QtYaml::variantDocumentsFromYaml(configYaml.isEmpty() ? qgetenv("AM_CONFIG")
- : configYaml);
- if (docs.size() == 1)
- m_configuration = docs.first().toMap();
+ try {
+ QVector<QVariant> docs = YamlParser::parseAllDocuments(configYaml.isEmpty() ? qgetenv("AM_CONFIG")
+ : configYaml);
+ if (docs.size() == 1)
+ m_configuration = docs.first().toMap();
+ } catch (const Exception &e) {
+ throw Exception("Runtime launcher could not parse the YAML configuration coming from the "
+ "application-manager: %1").arg(e.errorString());
+ }
m_baseDir = m_configuration.value(qSL("baseDir")).toString() + qL1C('/');
m_runtimeConfiguration = m_configuration.value(qSL("runtimeConfiguration")).toMap();
@@ -244,7 +254,7 @@ void LauncherMain::setupDBusConnections() Q_DECL_NOEXCEPT_EXPR(false)
if (!dbusConnection.isConnected())
throw Exception("could not connect to the P2P D-Bus via: %1").arg(m_dbusAddressP2P);
- qCDebug(LogQmlRuntime) << "Connected to the P2P D-Bus via:" << m_dbusAddressP2P;
+ qCDebug(LogRuntime) << "Connected to the P2P D-Bus via:" << m_dbusAddressP2P;
if (!m_dbusAddressNotifications.isEmpty()) {
if (m_dbusAddressNotifications == qL1S("system"))
@@ -257,7 +267,7 @@ void LauncherMain::setupDBusConnections() Q_DECL_NOEXCEPT_EXPR(false)
if (!dbusConnection.isConnected())
throw Exception("could not connect to the Notification D-Bus via: %1").arg(m_dbusAddressNotifications);
- qCDebug(LogQmlRuntime) << "Connected to the Notification D-Bus via:" << m_dbusAddressNotifications;
+ qCDebug(LogRuntime) << "Connected to the Notification D-Bus via:" << m_dbusAddressNotifications;
} else {
qCWarning(LogDeployment) << "Notifications are not supported by this configuration";
}
diff --git a/src/launcher-lib/launchermain.h b/src/launcher-lib/launchermain.h
index 7ff1dd31..e7589caf 100644
--- a/src/launcher-lib/launchermain.h
+++ b/src/launcher-lib/launchermain.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -45,31 +45,18 @@
#include <QtAppManCommon/global.h>
#include <QtAppManSharedMain/sharedmain.h>
-#if defined(AM_HEADLESS)
-# include <QCoreApplication>
-typedef QCoreApplication LauncherMainBase;
QT_FORWARD_DECLARE_CLASS(QWindow)
-#elif defined(AM_ENABLE_WIDGETS)
-# include <QApplication>
-# include <QSurfaceFormat>
-typedef QApplication LauncherMainBase;
-#else
-# include <QGuiApplication>
-# include <QSurfaceFormat>
-typedef QGuiApplication LauncherMainBase;
-#endif
-
QT_BEGIN_NAMESPACE_AM
class WaylandQtAMClientExtension;
-class LauncherMain : public LauncherMainBase, public SharedMain
+class LauncherMain : public QObject, public SharedMain
{
Q_OBJECT
public:
- LauncherMain(int &argc, char **argv) Q_DECL_NOEXCEPT;
- ~LauncherMain();
+ LauncherMain() Q_DECL_NOEXCEPT;
+ virtual ~LauncherMain();
static LauncherMain *instance();
@@ -107,6 +94,9 @@ signals:
void slowAnimationsChanged(bool slow);
private:
+ static LauncherMain *s_instance;
+ Q_DISABLE_COPY(LauncherMain)
+
QVariantMap m_configuration;
QString m_baseDir;
QVariantMap m_runtimeConfiguration;
diff --git a/src/launcher-lib/waylandqtamclientextension.cpp b/src/launcher-lib/waylandqtamclientextension.cpp
index 5cf4e8ad..58c3955a 100644
--- a/src/launcher-lib/waylandqtamclientextension.cpp
+++ b/src/launcher-lib/waylandqtamclientextension.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/launcher-lib/waylandqtamclientextension_p.h b/src/launcher-lib/waylandqtamclientextension_p.h
index 5dfb7f50..c2814855 100644
--- a/src/launcher-lib/waylandqtamclientextension_p.h
+++ b/src/launcher-lib/waylandqtamclientextension_p.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -59,8 +59,6 @@
// We mean it.
//
-QT_FORWARD_DECLARE_CLASS(QWaylandCompositor)
-QT_FORWARD_DECLARE_CLASS(QWaylandSurface)
QT_FORWARD_DECLARE_CLASS(QWindow)
QT_BEGIN_NAMESPACE_AM
diff --git a/src/main-lib/applicationinstaller.cpp b/src/main-lib/applicationinstaller.cpp
new file mode 100644
index 00000000..f9d66641
--- /dev/null
+++ b/src/main-lib/applicationinstaller.cpp
@@ -0,0 +1,477 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <qqml.h>
+#include <QQmlEngine>
+
+#include "applicationinstaller.h"
+
+
+/*!
+ \qmltype ApplicationInstaller
+ \inqmlmodule QtApplicationManager.SystemUI
+ \ingroup system-ui-singletons
+ \brief The package installation/removal/update part of the application-manager.
+
+ The ApplicationInstaller singleton type handles the package installation
+ part of the application manager. It provides both a DBus and QML APIs for
+ all of its functionality.
+
+ \note The ApplicationInstaller singleton and its corresponding DBus API are only available if you
+ specify a base directory for installed application manifests. See \l{Configuration} for details.
+
+ \target TaskStates
+
+ The following table describes all possible states that a background task could be in:
+
+ \table
+ \header
+ \li Task State
+ \li Description
+ \row
+ \li \c Queued
+ \li The task was created and is now queued up for execution.
+ \row
+ \li \c Executing
+ \li The task is being executed.
+ \row
+ \li \c Finished
+ \li The task was executed successfully.
+ \row
+ \li \c Failed
+ \li The task failed to execute successfully.
+ \row
+ \li \c AwaitingAcknowledge
+ \li \e{Installation tasks only!} The task is currently halted, waiting for either
+ acknowledgePackageInstallation() or cancelTask() to continue. See startPackageInstallation()
+ for more information on the installation workflow.
+ \row
+ \li \c Installing
+ \li \e{Installation tasks only!} The installation was acknowledged via acknowledgePackageInstallation()
+ and the final installation phase is now running.
+ \row
+ \li \c CleaningUp
+ \li \e{Installation tasks only!} The installation has finished, and previous installations as
+ well as temporary files are being cleaned up.
+ \endtable
+
+ The normal workflow for tasks is: \c Queued \unicode{0x2192} \c Executing \unicode{0x2192} \c
+ Finished. The task can enter the \c Failed state at any point though - either by being canceled via
+ cancelTask() or simply by failing due to an error.
+
+ Installation tasks are a bit more complex due to the acknowledgment: \c Queued \unicode{0x2192}
+ \c Executing \unicode{0x2192} \c AwaitingAcknowledge (this state may be skipped if
+ acknowledgePackageInstallation() was called already) \unicode{0x2192} \c Installing
+ \unicode{0x2192} \c Cleanup \unicode{0x2192} \c Finished. Again, the task can fail at any point.
+*/
+
+// THIS IS MISSING AN EXAMPLE!
+
+/*!
+ \qmlsignal ApplicationInstaller::taskStateChanged(string taskId, string newState)
+
+ This signal is emitted when the state of the task identified by \a taskId changes. The
+ new state is supplied in the parameter \a newState.
+
+ \sa taskState()
+*/
+
+/*!
+ \qmlsignal ApplicationInstaller::taskStarted(string taskId)
+
+ This signal is emitted when the task identified by \a taskId enters the \c Executing state.
+
+ \sa taskStateChanged()
+*/
+
+/*!
+ \qmlsignal ApplicationInstaller::taskFinished(string taskId)
+
+ This signal is emitted when the task identified by \a taskId enters the \c Finished state.
+
+ \sa taskStateChanged()
+*/
+
+/*!
+ \qmlsignal ApplicationInstaller::taskFailed(string taskId)
+
+ This signal is emitted when the task identified by \a taskId enters the \c Failed state.
+
+ \sa taskStateChanged()
+*/
+
+/*!
+ \qmlsignal ApplicationInstaller::taskRequestingInstallationAcknowledge(string taskId, object application, object packageExtraMetaData, object packageExtraSignedMetaData)
+
+ This signal is emitted when the installation task identified by \a taskId has received enough
+ meta-data to be able to emit this signal. The task may be in either \c Executing or \c
+ AwaitingAcknowledge state.
+
+ The contents of the package's manifest file are supplied via \a application as a JavaScript object.
+ Please see the \l {ApplicationManager Roles}{role names} for the expected object fields.
+
+ In addition, the package's extra meta-data (signed and unsinged) is also supplied via \a
+ packageExtraMetaData and \a packageExtraSignedMetaData respectively as JavaScript objects.
+ Both these objects are optional and need to be explicitly either populated during an
+ application's packaging step or added by an intermediary app-store server.
+ By default, both will just be empty.
+
+ Following this signal, either cancelTask() or acknowledgePackageInstallation() has to be called
+ for this \a taskId, to either cancel the installation or try to complete it.
+
+ The ApplicationInstaller has two convenience functions to help the System-UI with verifying the
+ meta-data: compareVersions() and, in case you are using reverse-DNS notation for application-ids,
+ validateDnsName().
+
+ \sa taskStateChanged(), startPackageInstallation()
+*/
+
+/*!
+ \qmlsignal ApplicationInstaller::taskBlockingUntilInstallationAcknowledge(string taskId)
+
+ This signal is emitted when the installation task identified by \a taskId cannot continue
+ due to a missing acknowledgePackageInstallation() call for the task.
+
+ \sa taskStateChanged(), acknowledgePackageInstallation()
+*/
+
+/*!
+ \qmlsignal ApplicationInstaller::taskProgressChanged(string taskId, qreal progress)
+
+ This signal is emitted whenever the task identified by \a taskId makes progress towards its
+ completion. The \a progress is reported as a floating-point number ranging from \c 0.0 to \c 1.0.
+
+ \sa taskStateChanged()
+*/
+
+QT_BEGIN_NAMESPACE_AM
+
+ApplicationInstaller *ApplicationInstaller::s_instance = nullptr;
+
+ApplicationInstaller::ApplicationInstaller(PackageManager *pm, QObject *parent)
+ : QObject(parent)
+ , m_pm(pm)
+{
+ // connect the APIs of the PackageManager and ApplicationInstaller
+ QObject::connect(pm, &PackageManager::taskProgressChanged,
+ this, &ApplicationInstaller::taskProgressChanged);
+ QObject::connect(pm, &PackageManager::taskStarted,
+ this, &ApplicationInstaller::taskStarted);
+ QObject::connect(pm, &PackageManager::taskFinished,
+ this, &ApplicationInstaller::taskFinished);
+ QObject::connect(pm, &PackageManager::taskFailed,
+ this, &ApplicationInstaller::taskFailed);
+ QObject::connect(pm, &PackageManager::taskStateChanged,
+ this, &ApplicationInstaller::taskStateChanged);
+ QObject::connect(pm, &PackageManager::taskRequestingInstallationAcknowledge,
+ this, &ApplicationInstaller::taskRequestingInstallationAcknowledge);
+ QObject::connect(pm, &PackageManager::taskBlockingUntilInstallationAcknowledge,
+ this, &ApplicationInstaller::taskBlockingUntilInstallationAcknowledge);
+}
+
+ApplicationInstaller::~ApplicationInstaller()
+{
+ s_instance = nullptr;
+}
+
+ApplicationInstaller *ApplicationInstaller::createInstance(PackageManager *pm)
+{
+ if (Q_UNLIKELY(s_instance))
+ qFatal("ApplicationInstaller::createInstance() was called a second time.");
+
+
+ qmlRegisterSingletonType<ApplicationInstaller>("QtApplicationManager.SystemUI", 2, 0, "ApplicationInstaller",
+ &ApplicationInstaller::instanceForQml);
+
+ return s_instance = new ApplicationInstaller(pm, QCoreApplication::instance());
+}
+
+ApplicationInstaller *ApplicationInstaller::instance()
+{
+ if (!s_instance)
+ qFatal("ApplicationInstaller::instance() was called before createInstance().");
+ return s_instance;
+}
+
+QObject *ApplicationInstaller::instanceForQml(QQmlEngine *, QJSEngine *)
+{
+ QQmlEngine::setObjectOwnership(instance(), QQmlEngine::CppOwnership);
+ return instance();
+}
+
+/*!
+ \qmlmethod list<string> ApplicationInstaller::installationLocationIds()
+
+ Retuns a list of all known installation location ids. Calling getInstallationLocation() on one of
+ the returned identifiers will yield specific information about the individual installation locations.
+*/
+
+/*!
+ \qmlmethod string ApplicationInstaller::installationLocationIdFromApplication(string id)
+
+ Returns the installation location id for the application identified by \a id. Returns
+ an empty string in case the application is not installed.
+
+ \sa installationLocationIds()
+*/
+
+/*!
+ \qmlmethod object ApplicationInstaller::getInstallationLocation(string installationLocationId)
+
+ Returns an object describing the installation location identified by \a installationLocationId in detail.
+
+ The returned object has the following members:
+
+ \table
+ \header
+ \li \c Name
+ \li \c Type
+ \li Description
+ \row
+ \li \c id
+ \li \c string
+ \li The installation location id that is used as the handle for all other ApplicationInstaller
+ function calls. The \c id consists of the \c type and \c index field, concatenated by
+ a single dash (for example, \c internal-0).
+ \row
+ \li \c type
+ \li \c string
+ \li The type of device this installation location is connected to. Valid values are \c
+ internal (for any kind of built-in storage, e.g. flash), \c removable (for any kind of
+ storage that is removable by the user, e.g. an SD card) and \c invalid.
+ \row
+ \li \c index
+ \li \c int
+ \li In case there is more than one installation location for the same type of device, this
+ \c zero-based index is used for disambiguation. For example, two SD card slots will
+ result in the ids \c removable-0 and \c removable-1. Otherwise, the index is always \c 0.
+ \row
+ \li \c isDefault
+ \li \c bool
+
+ \li Exactly one installation location is the default location which must be mounted and
+ accessible at all times. This can be used by an UI application to get a sensible
+ default for the installation location that it needs to pass to startPackageInstallation().
+ \row
+ \li \c isRemovable
+ \li \c bool
+ \li Indicates whether this installation location is on a removable media (for example, an SD
+ card).
+ \row
+ \li \c isMounted
+ \li \c bool
+ \li The current mount status of this installation location: should always be \c true for
+ non-removable media.
+ \row
+ \li \c installationPath
+ \li \c string
+ \li The absolute file-system path to the base directory under which applications are installed.
+ \row
+ \li \c installationDeviceSize
+ \li \c int
+ \li The size of the device holding \c installationPath in bytes. This field is only present if
+ \c isMounted is \c true.
+ \row
+ \li \c installationDeviceFree
+ \li \c int
+ \li The amount of bytes available on the device holding \c installationPath. This field is only
+ present if \c isMounted is \c true.
+ \row
+ \li \c documentPath
+ \li \c string
+ \li The absolute file-system path to the base directory under which per-user document
+ directories are created.
+ \row
+ \li \c documentDeviceSize
+ \li \c int
+ \li The size of the device holding \c documentPath in bytes. This field is only present if
+ \c isMounted is \c true.
+ \row
+ \li \c documentDeviceFree
+ \li \c int
+ \li The amount of bytes available on the device holding \c documentPath. This field is only
+ present if \c isMounted is \c true.
+ \endtable
+
+ Returns an empty object in case the \a installationLocationId is not valid.
+*/
+
+/*!
+ \qmlmethod int ApplicationInstaller::installedApplicationSize(string id)
+
+ Returns the size in bytes that the application identified by \a id is occupying on the storage
+ device.
+
+ Returns \c -1 in case the application \a id is not valid, or the application is not installed.
+*/
+
+/*!
+ \qmlmethod var ApplicationInstaller::installedApplicationExtraMetaData(string id)
+
+ Returns a map of all extra metadata in the package header of the application identified by \a id.
+
+ Returns an empty map in case the application \a id is not valid, or the application is not installed.
+*/
+
+/*!
+ \qmlmethod var ApplicationInstaller::installedApplicationExtraSignedMetaData(string id)
+
+ Returns a map of all signed extra metadata in the package header of the application identified
+ by \a id.
+
+ Returns an empty map in case the application \a id is not valid, or the application is not installed.
+*/
+
+/*! \internal
+ Type safe convenience function, since DBus does not like QUrl
+*/
+
+/*!
+ \qmlmethod string ApplicationInstaller::startPackageInstallation(string installationLocationId, string sourceUrl)
+
+ Downloads an application package from \a sourceUrl and installs it to the installation location
+ described by \a installationLocationId.
+
+ The actual download and installation will happen asynchronously in the background. The
+ ApplicationInstaller emits the signals \l taskStarted, \l taskProgressChanged, \l
+ taskRequestingInstallationAcknowledge, \l taskFinished, \l taskFailed, and \l taskStateChanged
+ for the returned taskId when applicable.
+
+ \note Simply calling this function is not enough to complete a package installation: The
+ taskRequestingInstallationAcknowledge() signal needs to be connected to a slot where the
+ supplied application meta-data can be validated (either programmatically or by asking the user).
+ If the validation is successful, the installation can be completed by calling
+ acknowledgePackageInstallation() or, if the validation was unsuccessful, the installation should
+ be canceled by calling cancelTask().
+ Failing to do one or the other will leave an unfinished "zombie" installation.
+
+ Returns a unique \c taskId. This can also be an empty string, if the task could not be
+ created (in this case, no signals will be emitted).
+*/
+
+/*!
+ \qmlmethod void ApplicationInstaller::acknowledgePackageInstallation(string taskId)
+
+ Calling this function enables the installer to complete the installation task identified by \a
+ taskId. Normally, this function is called after receiving the taskRequestingInstallationAcknowledge()
+ signal, and the user and/or the program logic decided to proceed with the installation.
+
+ \sa startPackageInstallation()
+ */
+
+/*!
+ \qmlmethod string ApplicationInstaller::removePackage(string id, bool keepDocuments, bool force)
+
+ Uninstalls the application identified by \a id. Normally, the documents directory of the
+ application is deleted on removal, but this can be prevented by setting \a keepDocuments to \c true.
+
+ The actual removal will happen asynchronously in the background. The ApplicationInstaller will
+ emit the signals \l taskStarted, \l taskProgressChanged, \l taskFinished, \l taskFailed and \l
+ taskStateChanged for the returned \c taskId when applicable.
+
+ Normally, \a force should only be set to \c true if a previous call to removePackage() failed.
+ This may be necessary if the installation process was interrupted, or if an SD card got lost
+ or has file-system issues.
+
+ Returns a unique \c taskId. This can also be an empty string, if the task could not be created
+ (in this case, no signals will be emitted).
+*/
+
+/*!
+ \qmlmethod enumeration ApplicationInstaller::taskState(string taskId)
+
+ Returns the current state of the installation task identified by \a taskId.
+ \l {TaskStates}{See here} for a list of valid task states.
+
+ Returns \c ApplicationInstaller.Invalid if the \a taskId is invalid.
+*/
+
+/*!
+ \qmlmethod string ApplicationInstaller::taskApplicationId(string taskId)
+
+ Returns the application id associated with the task identified by \a taskId. The task may not
+ have a valid application id at all times though and in this case the function will return an
+ empty string (this will be the case for installations before the taskRequestingInstallationAcknowledge
+ signal has been emitted).
+
+ Returns an empty string if the \a taskId is invalid.
+*/
+
+
+/*!
+ \qmlmethod list<string> ApplicationInstaller::activeTaskIds()
+
+ Retuns a list of all currently active (as in not yet finished or failed) installation task ids.
+*/
+
+/*!
+ \qmlmethod bool ApplicationInstaller::cancelTask(string taskId)
+
+ Tries to cancel the installation task identified by \a taskId.
+
+ Returns \c true if the task was canceled, \c false otherwise.
+*/
+
+/*!
+ \qmlmethod int ApplicationInstaller::compareVersions(string version1, string version2)
+
+ Convenience method for app-store implementations or taskRequestingInstallationAcknowledge()
+ callbacks for comparing version numbers, as the actual version comparison algorithm is not
+ trivial.
+
+ Returns \c -1, \c 0 or \c 1 if \a version1 is smaller than, equal to, or greater than \a
+ version2 (similar to how \c strcmp() works).
+*/
+
+/*!
+ \qmlmethod int ApplicationInstaller::validateDnsName(string name, int minimalPartCount)
+
+ Convenience method for app-store implementations or taskRequestingInstallationAcknowledge()
+ callbacks for checking if the given \a name is a valid DNS (or reverse-DNS) name according to
+ RFC 1035/1123. If the optional parameter \a minimalPartCount is specified, this function will
+ also check if \a name contains at least this amount of parts/sub-domains.
+
+ Returns \c true if the name is a valid DNS name or \c false otherwise.
+*/
+
+QT_END_NAMESPACE_AM
diff --git a/src/installer-lib/applicationinstaller.h b/src/main-lib/applicationinstaller.h
index 2afaeb85..f83ddadb 100644
--- a/src/installer-lib/applicationinstaller.h
+++ b/src/main-lib/applicationinstaller.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -47,19 +48,19 @@
#include <QUrl>
#include <QStringList>
#include <QDir>
+#include <QDebug>
#include <QtAppManCommon/error.h>
-#include <QtAppManInstaller/installationlocation.h>
-#include <QtAppManInstaller/asynchronoustask.h>
+#include <QtAppManCommon/logging.h>
+#include <QtAppManManager/applicationmanager.h>
+#include <QtAppManManager/packagemanager.h>
+#include <QtAppManManager/package.h>
+#include <QtAppManManager/asynchronoustask.h>
QT_FORWARD_DECLARE_CLASS(QQmlEngine)
QT_FORWARD_DECLARE_CLASS(QJSEngine)
QT_BEGIN_NAMESPACE_AM
-class ApplicationManager;
-class ApplicationInstallerPrivate;
-class SudoClient;
-
class ApplicationInstaller : public QObject
{
@@ -79,61 +80,100 @@ public:
Q_ENUMS(QT_PREPEND_NAMESPACE_AM(AsynchronousTask::TaskState))
~ApplicationInstaller();
- static ApplicationInstaller *createInstance(const QVector<InstallationLocation> &installationLocations,
- const QString &manifestDirPath,
- const QString &hardwareId, QString *error);
+ static ApplicationInstaller *createInstance(PackageManager *pm);
static ApplicationInstaller *instance();
static QObject *instanceForQml(QQmlEngine *qmlEngine, QJSEngine *);
- bool developmentMode() const;
- void setDevelopmentMode(bool b);
- bool allowInstallationOfUnsignedPackages() const;
- void setAllowInstallationOfUnsignedPackages(bool b);
- QString hardwareId() const;
-
- bool isApplicationUserIdSeparationEnabled() const;
- uint commonApplicationGroupId() const;
-
- bool enableApplicationUserIdSeparation(uint minUserId, uint maxUserId, uint commonGroupId);
-
- // Ownership of QDir* stays with ApplicationInstaller
- // Never returns null
- const QDir *manifestDirectory() const;
+ bool developmentMode() const { return m_pm->developmentMode(); }
+ bool allowInstallationOfUnsignedPackages() const { return m_pm->allowInstallationOfUnsignedPackages(); }
+ QString hardwareId() const { return m_pm->hardwareId(); }
- bool setDBusPolicy(const QVariantMap &yamlFragment);
- void setCACertificates(const QList<QByteArray> &chainOfTrust);
-
- void cleanupBrokenInstallations() const Q_DECL_NOEXCEPT_EXPR(false);
-
- // InstallationLocation handling
- QVector<InstallationLocation> installationLocations() const;
- const InstallationLocation &defaultInstallationLocation() const;
- const InstallationLocation &installationLocationFromId(const QString &installationLocationId) const;
- const InstallationLocation &installationLocationFromApplication(const QString &id) const;
+ bool isApplicationUserIdSeparationEnabled() const { return m_pm->isApplicationUserIdSeparationEnabled(); }
+ uint commonApplicationGroupId() const { return m_pm->commonApplicationGroupId(); }
// Q_SCRIPTABLEs are available via both QML and D-Bus
- Q_SCRIPTABLE QStringList installationLocationIds() const;
- Q_SCRIPTABLE QString installationLocationIdFromApplication(const QString &id) const;
- Q_SCRIPTABLE QVariantMap getInstallationLocation(const QString &installationLocationId) const;
+ Q_SCRIPTABLE QStringList installationLocationIds() const { return { qL1S("internal-0") }; }
+ Q_SCRIPTABLE QString installationLocationIdFromApplication(const QString &applicationId) const
+ {
+ auto app = ApplicationManager::instance()->fromId(applicationId);
+ if (app && ((!app->package()->isBuiltIn() || app->package()->builtInHasRemovableUpdate())))
+ return qL1S("internal-0");
+ return QString();
+ }
+ Q_SCRIPTABLE QVariantMap getInstallationLocation(const QString &installationLocationId) const
+ {
+ if (installationLocationId != qL1S("internal-0"))
+ return QVariantMap { };
+
+ auto iloc = m_pm->installationLocation();
+ auto dloc = m_pm->documentLocation();
+
+ return QVariantMap {
+ { qSL("id"), qSL("internal-0") },
+ { qSL("type"), qSL("internal") },
+ { qSL("index"), 0 },
+ { qSL("isDefault"), true },
+ { qSL("installationPath"), iloc.value(qL1S("path")) },
+ { qSL("installationDeviceSize"), iloc.value(qL1S("size")) },
+ { qSL("installationDeviceFree"), iloc.value(qL1S("free")) },
+ { qSL("documentPath"), dloc.value(qL1S("path")) },
+ { qSL("documentDeviceSize"), dloc.value(qL1S("size")) },
+ { qSL("documentDeviceFree"), dloc.value(qL1S("free")) }
+ };
+ }
// all QString return values are task-ids
- QString startPackageInstallation(const QString &installationLocationId, const QUrl &sourceUrl);
- Q_SCRIPTABLE QString startPackageInstallation(const QString &installationLocationId, const QString &sourceUrl);
- Q_SCRIPTABLE void acknowledgePackageInstallation(const QString &taskId);
- Q_SCRIPTABLE QString removePackage(const QString &id, bool keepDocuments, bool force = false);
-
- Q_SCRIPTABLE AsynchronousTask::TaskState taskState(const QString &taskId) const;
- Q_SCRIPTABLE QString taskApplicationId(const QString &taskId) const;
- Q_SCRIPTABLE QStringList activeTaskIds() const;
- Q_SCRIPTABLE bool cancelTask(const QString &taskId);
+ Q_SCRIPTABLE QString startPackageInstallation(const QString &installationLocationId, const QString &sourceUrl)
+ {
+ if (installationLocationId == qL1S("internal-0")) {
+ return m_pm->startPackageInstallation(sourceUrl);
+ } else {
+ qCWarning(LogInstaller) << "The only supported legacy installation location is 'internal-0', "
+ "but an installation was requested to:" << installationLocationId;
+ return QString();
+ }
+ }
+
+ Q_SCRIPTABLE void acknowledgePackageInstallation(const QString &taskId)
+ { return m_pm->acknowledgePackageInstallation(taskId); }
+ Q_SCRIPTABLE QString removePackage(const QString &packageId, bool keepDocuments, bool force = false)
+ { return m_pm->removePackage(packageId, keepDocuments, force); }
+
+ Q_SCRIPTABLE AsynchronousTask::TaskState taskState(const QString &taskId) const
+ { return m_pm->taskState(taskId); }
+ Q_SCRIPTABLE QString taskApplicationId(const QString &taskId) const
+ {
+ auto package = m_pm->fromId(m_pm->taskPackageId(taskId));
+ if (package && !package->info()->applications().isEmpty())
+ return package->info()->applications().constFirst()->id();
+ return QString();
+ }
+ Q_SCRIPTABLE QStringList activeTaskIds() const
+ { return m_pm->activeTaskIds(); }
+ Q_SCRIPTABLE bool cancelTask(const QString &taskId)
+ { return m_pm->cancelTask(taskId); }
// convenience function for app-store implementations
- Q_SCRIPTABLE int compareVersions(const QString &version1, const QString &version2);
- Q_SCRIPTABLE bool validateDnsName(const QString &name, int minimumParts = 1);
-
- Q_SCRIPTABLE qint64 installedApplicationSize(const QString &id) const;
- Q_SCRIPTABLE QVariantMap installedApplicationExtraMetaData(const QString &id) const;
- Q_SCRIPTABLE QVariantMap installedApplicationExtraSignedMetaData(const QString &id) const;
+ Q_SCRIPTABLE int compareVersions(const QString &version1, const QString &version2)
+ { return m_pm->compareVersions(version1, version2); }
+ Q_SCRIPTABLE bool validateDnsName(const QString &name, int minimumParts = 1)
+ { return m_pm->validateDnsName(name, minimumParts); }
+
+ Q_SCRIPTABLE qint64 installedApplicationSize(const QString &applicationId) const
+ {
+ auto app = ApplicationManager::instance()->fromId(applicationId);
+ return m_pm->installedPackageSize(app ? app->package()->id() : QString());
+ }
+ Q_SCRIPTABLE QVariantMap installedApplicationExtraMetaData(const QString &applicationId) const
+ {
+ auto app = ApplicationManager::instance()->fromId(applicationId);
+ return m_pm->installedPackageExtraMetaData(app ? app->package()->id() : QString());
+ }
+ Q_SCRIPTABLE QVariantMap installedApplicationExtraSignedMetaData(const QString &applicationId) const
+ {
+ auto app = ApplicationManager::instance()->fromId(applicationId);
+ return m_pm->installedPackageExtraSignedMetaData(app ? app->package()->id() : QString());
+ }
signals:
Q_SCRIPTABLE void taskStarted(const QString &taskId);
@@ -150,29 +190,12 @@ signals:
const QVariantMap &packageExtraSignedMetaData);
Q_SCRIPTABLE void taskBlockingUntilInstallationAcknowledge(const QString &taskId);
-private slots:
- void executeNextTask();
private:
- void cleanupMounts() const;
- void triggerExecuteNextTask();
- QString enqueueTask(AsynchronousTask *task);
- void handleFailure(AsynchronousTask *task);
-
- QList<QByteArray> caCertificates() const;
-
- uint findUnusedUserId() const Q_DECL_NOEXCEPT_EXPR(false);
-
-private:
- // Ownership of manifestDir and iamgeMountDir is passed to ApplicationInstaller
- ApplicationInstaller(const QVector<InstallationLocation> &installationLocations, QDir *manifestDir, const QString &hardwareId, QObject *parent);
+ PackageManager *m_pm;
+ ApplicationInstaller(PackageManager *pm, QObject *parent = nullptr);
ApplicationInstaller(const ApplicationInstaller &);
static ApplicationInstaller *s_instance;
-
- ApplicationInstallerPrivate *d;
-
- friend class InstallationTask;
- friend class DeinstallationTask;
};
QT_END_NAMESPACE_AM
diff --git a/src/main-lib/configuration.cpp b/src/main-lib/configuration.cpp
index 313bc861..371275cb 100644
--- a/src/main-lib/configuration.cpp
+++ b/src/main-lib/configuration.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -40,171 +41,188 @@
**
****************************************************************************/
-#include <QFile>
-#include <QFileInfo>
#include <QCoreApplication>
-#include <QDebug>
+#include <QFile>
#include <QStandardPaths>
+#include <QMetaEnum>
+#include <QProcessEnvironment>
+#include <private/qvariant_p.h>
+
#include <QDataStream>
-#include <QCryptographicHash>
-#include <QElapsedTimer>
-#include <QtConcurrent/QtConcurrent>
+#include <QFileInfo>
+#include <QDir>
+#include <QBuffer>
+
+#if !defined(AM_HEADLESS)
+# include <QGuiApplication>
+#endif
#include <functional>
+#if defined(Q_OS_LINUX)
+# include <sys/file.h>
+#endif
+
#include "global.h"
#include "logging.h"
#include "qtyaml.h"
+#include "configcache.h"
#include "utilities.h"
#include "exception.h"
-#include "qml-utilities.h"
+#include "utilities.h"
#include "configuration.h"
-
-// enable this to benchmark the config cache
-//#define AM_TIME_CONFIG_PARSING
-
-// use QtConcurrent to parse the config files, if there are more than x config files
-#define AM_PARALLEL_THRESHOLD 1
+#include "configuration_p.h"
QT_BEGIN_NAMESPACE_AM
-template<> bool Configuration::value(const char *clname, const QVector<const char *> &cfname) const
+template<> bool Configuration::value(const char *clname, const bool &cfvalue) const
{
- return (clname && m_clp.isSet(qL1S(clname))) || findInConfigFile(cfname).toBool();
+ return (clname && m_clp.isSet(qL1S(clname))) || cfvalue;
}
-template<> QString Configuration::value(const char *clname, const QVector<const char *> &cfname) const
+template<> QString Configuration::value(const char *clname, const QString &cfvalue) const
{
- QString clval;
- if (clname)
- clval = m_clp.value(qL1S(clname));
- bool cffound;
- QString cfval = findInConfigFile(cfname, &cffound).toString();
- return ((clname && m_clp.isSet(qL1S(clname))) || !cffound) ? clval : cfval;
+ return (clname && m_clp.isSet(qL1S(clname))) ? m_clp.value(qL1S(clname)) : cfvalue;
}
-template<> QStringList Configuration::value(const char *clname, const QVector<const char *> &cfname) const
+template<> QStringList Configuration::value(const char *clname, const QStringList &cfvalue) const
{
QStringList result;
if (clname)
result = m_clp.values(qL1S(clname));
- if (!cfname.isEmpty())
- result += variantToStringList(findInConfigFile(cfname));
+ if (!cfvalue.isEmpty())
+ result += cfvalue;
return result;
}
-template<> QVariant Configuration::value(const char *clname, const QVector<const char *> &cfname) const
-{
- QString yaml;
- if (clname)
- yaml = m_clp.value(qL1S(clname));
- if (!yaml.isEmpty()) {
- auto docs = QtYaml::variantDocumentsFromYaml(yaml.toUtf8());
- return docs.isEmpty() ? QVariant() : docs.constFirst();
- } else {
- return findInConfigFile(cfname);
- }
-}
-QVariant Configuration::findInConfigFile(const QVector<const char *> &path, bool *found) const
+// the templated adaptor class needed to instantiate ConfigCache<ConfigurationData> in parse() below
+template<> class ConfigCacheAdaptor<ConfigurationData>
{
- if (found)
- *found = false;
-
- if (path.isEmpty())
- return QVariant();
-
- QVariantMap var = m_config;
-
- for (int i = 0; i < (path.size() - 1); ++i) {
- QVariant subvar = var.value(qL1S(path.at(i)));
- if (subvar.type() == QVariant::Map)
- var = subvar.toMap();
- else
- return QVariant();
+public:
+ static ConfigurationData *loadFromSource(QIODevice *source, const QString &fileName)
+ {
+ return ConfigurationData::loadFromSource(source, fileName);
}
- if (found)
- *found = var.contains(qL1S(path.last()));
- return var.value(qL1S(path.last()));
-}
-
-void Configuration::mergeConfig(const QVariantMap &other)
-{
- recursiveMergeVariantMap(m_config, other);
-}
-
-QByteArray Configuration::substituteVars(const QByteArray &str, const QString &fileName,
- QStringList *deploymentWarnings)
-{
- QByteArray string = str;
- int posBeg = -1;
- int posEnd = -1;
- while (true) {
- if ((posBeg = string.indexOf("${", posEnd + 1)) < 0)
- break;
- if ((posEnd = string.indexOf('}', posBeg + 2)) < 0)
- break;
-
- const QByteArray varName = string.mid(posBeg + 2, posEnd - posBeg - 2);
-
- QByteArray varValue;
- if (varName == "CONFIG_PWD") {
- static QByteArray path;
- if (path.isEmpty() && !fileName.isEmpty())
- path = QFileInfo(fileName).path().toUtf8();
- varValue = path;
- } else if (varName.startsWith("env:")) {
- varValue = qgetenv(varName.constData() + 4);
- } else if (varName.startsWith("stdpath:")) {
- bool exists;
- int loc = QMetaEnum::fromType<QStandardPaths::StandardLocation>().keyToValue(varName.constData() + 8, &exists);
- if (exists)
- varValue = QStandardPaths::writableLocation(static_cast<QStandardPaths::StandardLocation>(loc)).toUtf8();
- }
-
- if (varValue.isEmpty() && deploymentWarnings) {
- *deploymentWarnings << qL1S("Could not replace variable ${") + qL1S(varName)
- + qL1S("} while parsing ") + fileName;
- continue;
- }
- string.replace(posBeg, varName.length() + 3, varValue);
- // varName and varValue most likely have a different length, so we have to adjust
- posEnd = posEnd - 3 - varName.length() + varValue.length();
+ void preProcessSourceContent(QByteArray &sourceContent, const QString &fileName)
+ {
+ sourceContent = ConfigurationData::substituteVars(sourceContent, fileName, warnings);
}
- return string;
-}
+ ConfigurationData *loadFromCache(QDataStream &ds)
+ {
+ return ConfigurationData::loadFromCache(ds);
+ }
+ void saveToCache(QDataStream &ds, const ConfigurationData *cd)
+ {
+ cd->saveToCache(ds);
+ }
+ static void merge(ConfigurationData *to, const ConfigurationData *from)
+ {
+ to->mergeFrom(from);
+ }
+ QStringList *warnings;
+};
+
+Configuration::Configuration(const char *additionalDescription,
+ bool onlyOnePositionalArgument)
+ : Configuration(QStringList(), qSL(":/build-config.yaml"),
+ additionalDescription, onlyOnePositionalArgument)
+{ }
-Configuration::Configuration(const QStringList &defaultConfigFilePaths, const QString &buildConfigFilePath)
+Configuration::Configuration(const QStringList &defaultConfigFilePaths,
+ const QString &buildConfigFilePath,
+ const char *additionalDescription,
+ bool onlyOnePositionalArgument)
: m_defaultConfigFilePaths(defaultConfigFilePaths)
, m_buildConfigFilePath(buildConfigFilePath)
+ , m_onlyOnePositionalArgument(onlyOnePositionalArgument)
{
- m_clp.addHelpOption();
- m_clp.addVersionOption();
- QCommandLineOption cf { { qSL("c"), qSL("config-file") }, qSL("load cnfiguration from file (can be given multiple times)."), qSL("files") };
+ // using QStringLiteral for all strings here adds a few KB of ro-data, but will also improve
+ // startup times slightly: less allocations and copies. MSVC cannot cope with multi-line though
+
+ const char *description =
+ "In addition to the commandline options below, the following environment\n"
+ "variables can be set:\n\n"
+ " AM_STARTUP_TIMER If set to 1, a startup performance analysis will be printed\n"
+ " on the console. Anything other than 1 will be interpreted\n"
+ " as the name of a file that is used instead of the console.\n"
+ "\n"
+ " AM_FORCE_COLOR_OUTPUT Can be set to 'on' to force color output to the console\n"
+ " and to 'off' to disable it. Any other value will result\n"
+ " in the default, auto-detection behavior.\n";
+
+ m_clp.setApplicationDescription(qSL("\n") + QCoreApplication::applicationName() + qSL("\n\n")
+ + (additionalDescription ? (qL1S(additionalDescription) + qSL("\n\n")) : QString())
+ + qL1S(description));
+
+ m_clp.addOption({ { qSL("h"), qSL("help")
+#if defined(Q_OS_WINDOWS)
+ , qSL("?")
+#endif
+ }, qSL("Displays this help.") });
+ m_clp.addOption({ qSL("version"), qSL("Displays version information.") });
+ QCommandLineOption cf { { qSL("c"), qSL("config-file") },
+ qSL("Load configuration from file (can be given multiple times)."), qSL("files") };
cf.setDefaultValues(m_defaultConfigFilePaths);
m_clp.addOption(cf);
- m_clp.addOption({ { qSL("o"), qSL("option") }, qSL("override a specific config option."), qSL("yaml-snippet") });
- m_clp.addOption({ qSL("no-config-cache"), qSL("disable the use of the config file cache.") });
- m_clp.addOption({ qSL("clear-config-cache"), qSL("ignore an existing config file cache.") });
+ m_clp.addOption({ { qSL("o"), qSL("option") }, qSL("Override a specific config option."), qSL("yaml-snippet") });
+ m_clp.addOption({ { qSL("no-cache"), qSL("no-config-cache") },
+ qSL("Disable the use of the config and appdb file cache.") });
+ m_clp.addOption({ { qSL("clear-cache"), qSL("clear-config-cache") },
+ qSL("Ignore an existing config and appdb file cache.") });
+ m_clp.addOption({ { qSL("r"), qSL("recreate-database") },
+ qSL("Backwards compatibility: synonyms for --clear-cache.") });
if (!buildConfigFilePath.isEmpty())
- m_clp.addOption({ qSL("build-config"), qSL("dumps the build configuration and exits.") });
+ m_clp.addOption({ qSL("build-config"), qSL("Dumps the build configuration and exits.") });
+
+ m_clp.addPositionalArgument(qSL("qml-file"), qSL("The main QML file."));
+ m_clp.addOption({ qSL("database"), qSL("Deprecated (ingored)."), qSL("file") });
+ m_clp.addOption({ qSL("builtin-apps-manifest-dir"), qSL("Base directory for built-in application manifests."), qSL("dir") });
+ m_clp.addOption({ qSL("installation-dir"), qSL("Base directory for package installations."), qSL("dir") });
+ m_clp.addOption({ qSL("document-dir"), qSL("Base directory for per-package document directories."), qSL("dir") });
+ m_clp.addOption({ qSL("installed-apps-manifest-dir"), qSL("Deprecated (ignored)."), qSL("dir") });
+ m_clp.addOption({ qSL("app-image-mount-dir"), qSL("Deprecated (ignored)."), qSL("dir") });
+ m_clp.addOption({ qSL("disable-installer"), qSL("Disable the application installer sub-system.") });
+ m_clp.addOption({ qSL("disable-intents"), qSL("Disable the intents sub-system.") });
+#if defined(QT_DBUS_LIB)
+ m_clp.addOption({ qSL("dbus"), qSL("Register on the specified D-Bus."), qSL("<bus>|system|session|none|auto"), qSL("auto") });
+ m_clp.addOption({ qSL("start-session-dbus"), qSL("Deprecated (ignored).") });
+#endif
+ m_clp.addOption({ qSL("fullscreen"), qSL("Display in full-screen.") });
+ m_clp.addOption({ qSL("no-fullscreen"), qSL("Do not display in full-screen.") });
+ m_clp.addOption({ qSL("I"), qSL("Additional QML import path."), qSL("dir") });
+ m_clp.addOption({ { qSL("v"), qSL("verbose") }, qSL("Verbose output.") });
+ m_clp.addOption({ qSL("slow-animations"), qSL("Run all animations in slow motion.") });
+ m_clp.addOption({ qSL("load-dummydata"), qSL("Loads QML dummy-data.") });
+ m_clp.addOption({ qSL("no-security"), qSL("Disables all security related checks (dev only!)") });
+ m_clp.addOption({ qSL("development-mode"), qSL("Enable development mode, allowing installation of dev-signed packages.") });
+ m_clp.addOption({ qSL("no-ui-watchdog"), qSL("Disables detecting hung UI applications (e.g. via Wayland's ping/pong).") });
+ m_clp.addOption({ qSL("no-dlt-logging"), qSL("Disables logging using automotive DLT.") });
+ m_clp.addOption({ qSL("force-single-process"), qSL("Forces single-process mode even on a wayland enabled build.") });
+ m_clp.addOption({ qSL("force-multi-process"), qSL("Forces multi-process mode. Will exit immediately if this is not possible.") });
+ m_clp.addOption({ qSL("wayland-socket-name"), qSL("Use this file name to create the wayland socket."), qSL("socket") });
+ m_clp.addOption({ qSL("single-app"), qSL("Runs a single application only (ignores the database)"), qSL("info.yaml file") }); // rename single-package
+ m_clp.addOption({ qSL("logging-rule"), qSL("Adds a standard Qt logging rule."), qSL("rule") });
+ m_clp.addOption({ qSL("qml-debug"), qSL("Enables QML debugging and profiling.") });
+ m_clp.addOption({ qSL("enable-touch-emulation"), qSL("Enables the touch emulation, converting mouse to touch events.") });
}
QVariant Configuration::buildConfig() const
{
QFile f(m_buildConfigFilePath);
- if (f.open(QFile::ReadOnly))
- return QtYaml::variantDocumentsFromYaml(f.readAll()).toList();
- else
- return QVariant();
+ if (f.open(QFile::ReadOnly)) {
+ try {
+ return YamlParser::parseAllDocuments(f.readAll()).toList();
+ } catch (...) {
+ }
+ }
+ return QVariant();
}
Configuration::~Configuration()
-{
-
-}
+{ }
// vvvv copied from QCommandLineParser ... why is this not public API?
@@ -289,198 +307,890 @@ void Configuration::parseWithArguments(const QStringList &arguments, QStringList
QStringList configFilePaths = m_clp.values(qSL("config-file"));
- struct ConfigFile
- {
- QString filePath; // abs. file path
- QByteArray checksum; // sha1 (fast and sufficient for this use-case)
- QByteArray content;
- QVariantMap config;
- };
- QVarLengthArray<ConfigFile> configFiles(configFilePaths.size());
+ AbstractConfigCache::Options cacheOptions = AbstractConfigCache::MergedResult;
+ if (noCache())
+ cacheOptions |= AbstractConfigCache::NoCache;
+ if (clearCache())
+ cacheOptions |= AbstractConfigCache::ClearCache;
- for (int i = 0; i < configFiles.size(); ++i)
- configFiles[i].filePath = QFileInfo(configFilePaths.at(i)).absoluteFilePath();
+ if (configFilePaths.isEmpty()) {
+ m_data = new ConfigurationData();
+ } else {
+ ConfigCache<ConfigurationData> cache(configFilePaths, qSL("config"), cacheOptions);
- bool noConfigCache = m_clp.isSet(qSL("no-config-cache"));
- bool clearConfigCache = m_clp.isSet(qSL("clear-config-cache"));
+ try {
+ cache.parse(deploymentWarnings);
+ m_data = cache.takeMergedResult();
+ } catch (const Exception &e) {
+ showParserMessage(e.errorString() + qL1C('\n'), ErrorMessage);
+ exit(1);
+ }
+ }
- const QDir cacheLocation = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
+ const QStringList options = m_clp.values(qSL("o"));
+ for (const QString &option : options) {
+ QByteArray yaml("formatVersion: 1\nformatType: am-configuration\n---\n");
+ yaml.append(option.toUtf8());
+ QBuffer buffer(&yaml);
+ buffer.open(QIODevice::ReadOnly);
+ try {
+ ConfigurationData *cd = ConfigCacheAdaptor<ConfigurationData>::loadFromSource(&buffer, qSL("command line"));
+ if (cd)
+ ConfigCacheAdaptor<ConfigurationData>::merge(m_data, cd);
+ } catch (const Exception &e) {
+ showParserMessage(QString::fromLatin1("Could not parse --option value: %1.\n")
+ .arg(e.errorString()),
+ ErrorMessage);
+ exit(1);
+ }
+ }
- if (!cacheLocation.exists())
- cacheLocation.mkpath(qSL("."));
+ // early sanity checks
+ if (m_onlyOnePositionalArgument && (m_clp.positionalArguments().size() > 1)) {
+ showParserMessage(qL1S("Only one main qml file can be specified.\n"), ErrorMessage);
+ exit(1);
+ }
- const QString cacheFilePath = cacheLocation.absoluteFilePath(qSL("appman-config.cache"));
+ if (installationDir().isEmpty()) {
+ const auto ilocs = m_data->installationLocations;
+ if (!ilocs.isEmpty() && deploymentWarnings)
+ *deploymentWarnings << qL1S("Support for \"installationLocations\" in the main config file has been removed:");
+
+ for (const auto iloc : ilocs) {
+ QVariantMap map = iloc.toMap();
+ QString id = map.value(qSL("id")).toString();
+ if (id == qSL("internal-0")) {
+ m_installationDir = map.value(qSL("installationPath")).toString();
+ m_documentDir = map.value(qSL("documentPath")).toString();
+ if (deploymentWarnings)
+ *deploymentWarnings << qL1S(" * still using installation location \"internal-0\" for backward compatibility");
+ } else if (deploymentWarnings) {
+ *deploymentWarnings << qL1S(" * ignoring installation location ") + id;
+ }
+ }
+ }
- QFile cacheFile(cacheFilePath);
- QAtomicInt useCache = false;
- QVariantMap cache;
+ if (installationDir().isEmpty() && deploymentWarnings) {
+ *deploymentWarnings << qL1S("No --installation-dir command line parameter or"
+ " applications/installationDir configuration key specified. It won't be possible to install,"
+ " remove or access installable packages.");
+ }
- static const quint32 CacheMagicHeader = 0xe42ad845;
+ if (value<bool>("start-session-dbus") && deploymentWarnings)
+ *deploymentWarnings << qL1S("Option \"--start-session-dbus\" has been deprecated and will be ignored.");
+}
- if (!noConfigCache && !clearConfigCache) {
- if (cacheFile.open(QFile::ReadOnly)) {
- try {
- QDataStream ds(&cacheFile);
- quint32 magic;
- ds >> magic;
+ConfigurationData *ConfigurationData::loadFromCache(QDataStream &ds)
+{
+ // IMPORTANT: when doing changes to ConfigurationData, remember to adjust all of
+ // loadFromCache(), saveToCache() and mergeFrom() at the same time!
+
+ ConfigurationData *cd = new ConfigurationData;
+ ds >> cd->runtimes.configurations
+ >> cd->containers.configurations
+ >> cd->containers.selection
+ >> cd->intents.disable
+ >> cd->intents.timeouts.disambiguation
+ >> cd->intents.timeouts.startApplication
+ >> cd->intents.timeouts.replyFromApplication
+ >> cd->intents.timeouts.replyFromSystem
+ >> cd->plugins.startup
+ >> cd->plugins.container
+ >> cd->logging.dlt.id
+ >> cd->logging.dlt.description
+ >> cd->logging.rules
+ >> cd->logging.messagePattern
+ >> cd->logging.useAMConsoleLogger
+ >> cd->installer.disable
+ >> cd->installer.caCertificates
+ >> cd->installer.applicationUserIdSeparation.maxUserId
+ >> cd->installer.applicationUserIdSeparation.minUserId
+ >> cd->installer.applicationUserIdSeparation.commonGroupId
+ >> cd->dbus.policies
+ >> cd->dbus.registrations
+ >> cd->quicklaunch.idleLoad
+ >> cd->quicklaunch.runtimesPerContainer
+ >> cd->ui.style
+ >> cd->ui.mainQml
+ >> cd->ui.resources
+ >> cd->ui.fullscreen
+ >> cd->ui.windowIcon
+ >> cd->ui.importPaths
+ >> cd->ui.pluginPaths
+ >> cd->ui.iconThemeName
+ >> cd->ui.loadDummyData
+ >> cd->ui.enableTouchEmulation
+ >> cd->ui.iconThemeSearchPaths
+ >> cd->ui.opengl
+ >> cd->applications.builtinAppsManifestDir
+ >> cd->applications.installationDir
+ >> cd->applications.documentDir
+ >> cd->installationLocations
+ >> cd->crashAction
+ >> cd->systemProperties
+ >> cd->flags.noSecurity
+ >> cd->flags.noUiWatchdog
+ >> cd->flags.developmentMode
+ >> cd->flags.forceMultiProcess
+ >> cd->flags.forceSingleProcess;
+ return cd;
+}
- if (magic != CacheMagicHeader)
- throw Exception("failed to read config cache header");
+void ConfigurationData::saveToCache(QDataStream &ds) const
+{
+ // IMPORTANT: when doing changes to ConfigurationData, remember to adjust all of
+ // loadFromCache(), saveToCache() and mergeFrom() at the same time!
+
+ ds << runtimes.configurations
+ << containers.configurations
+ << containers.selection
+ << intents.disable
+ << intents.timeouts.disambiguation
+ << intents.timeouts.startApplication
+ << intents.timeouts.replyFromApplication
+ << intents.timeouts.replyFromSystem
+ << plugins.startup
+ << plugins.container
+ << logging.dlt.id
+ << logging.dlt.description
+ << logging.rules
+ << logging.messagePattern
+ << logging.useAMConsoleLogger
+ << installer.disable
+ << installer.caCertificates
+ << installer.applicationUserIdSeparation.maxUserId
+ << installer.applicationUserIdSeparation.minUserId
+ << installer.applicationUserIdSeparation.commonGroupId
+ << dbus.policies
+ << dbus.registrations
+ << quicklaunch.idleLoad
+ << quicklaunch.runtimesPerContainer
+ << ui.style
+ << ui.mainQml
+ << ui.resources
+ << ui.fullscreen
+ << ui.windowIcon
+ << ui.importPaths
+ << ui.pluginPaths
+ << ui.iconThemeName
+ << ui.loadDummyData
+ << ui.enableTouchEmulation
+ << ui.iconThemeSearchPaths
+ << ui.opengl
+ << applications.builtinAppsManifestDir
+ << applications.installationDir
+ << applications.documentDir
+ << installationLocations
+ << crashAction
+ << systemProperties
+ << flags.noSecurity
+ << flags.noUiWatchdog
+ << flags.developmentMode
+ << flags.forceMultiProcess
+ << flags.forceSingleProcess;
+}
- QVector<QPair<QString, QByteArray>> configChecksums; // abs. file path -> sha1
- ds >> configChecksums >> cache;
+// templates would we way nicer, but we cannot get nice pointers-to-member-data for all elements in
+// our sub-structs in a generic way without a lot of boilerplate code
+#define MERGE_SCALAR(x) if (from->x != def.x) { this->x = from->x; } else { }
+#define MERGE_LIST(x) this->x.append(from->x)
+#define MERGE_MAP(x) recursiveMergeVariantMap(this->x, from->x)
- if (ds.status() != QDataStream::Ok)
- throw Exception("failed to read config cache content");
+void ConfigurationData::mergeFrom(const ConfigurationData *from)
+{
+ // IMPORTANT: when doing changes to ConfigurationData, remember to adjust all of
+ // loadFromCache(), saveToCache() and mergeFrom() at the same time!
+
+ static const ConfigurationData def;
+
+ MERGE_MAP(runtimes.configurations);
+ MERGE_MAP(containers.configurations);
+
+ MERGE_SCALAR(intents.disable);
+ MERGE_SCALAR(intents.timeouts.disambiguation);
+ MERGE_SCALAR(intents.timeouts.startApplication);
+ MERGE_SCALAR(intents.timeouts.replyFromApplication);
+ MERGE_SCALAR(intents.timeouts.replyFromSystem);
+ MERGE_LIST(plugins.startup);
+ MERGE_LIST(plugins.container);
+ MERGE_SCALAR(logging.dlt.id);
+ MERGE_SCALAR(logging.dlt.description);
+ MERGE_LIST(logging.rules);
+ MERGE_LIST(logging.messagePattern);
+ MERGE_SCALAR(logging.useAMConsoleLogger);
+ MERGE_SCALAR(installer.disable);
+ MERGE_LIST(installer.caCertificates);
+ MERGE_SCALAR(installer.applicationUserIdSeparation.maxUserId);
+ MERGE_SCALAR(installer.applicationUserIdSeparation.minUserId);
+ MERGE_SCALAR(installer.applicationUserIdSeparation.commonGroupId);
+ MERGE_MAP(dbus.policies);
+ MERGE_MAP(dbus.registrations);
+ MERGE_SCALAR(quicklaunch.idleLoad);
+ MERGE_SCALAR(quicklaunch.runtimesPerContainer);
+ MERGE_SCALAR(ui.style);
+ MERGE_SCALAR(ui.mainQml);
+ MERGE_LIST(ui.resources);
+ MERGE_SCALAR(ui.fullscreen);
+ MERGE_SCALAR(ui.windowIcon);
+ MERGE_LIST(ui.importPaths);
+ MERGE_LIST(ui.pluginPaths);
+ MERGE_SCALAR(ui.iconThemeName);
+ MERGE_SCALAR(ui.loadDummyData);
+ MERGE_SCALAR(ui.enableTouchEmulation);
+ MERGE_LIST(ui.iconThemeSearchPaths);
+ MERGE_MAP(ui.opengl);
+ MERGE_LIST(applications.builtinAppsManifestDir);
+ MERGE_SCALAR(applications.installationDir);
+ MERGE_SCALAR(applications.documentDir);
+ MERGE_LIST(installationLocations);
+ MERGE_MAP(crashAction);
+ MERGE_MAP(systemProperties);
+ MERGE_SCALAR(flags.noSecurity);
+ MERGE_SCALAR(flags.noUiWatchdog);
+ MERGE_SCALAR(flags.developmentMode);
+ MERGE_SCALAR(flags.forceMultiProcess);
+ MERGE_SCALAR(flags.forceSingleProcess);
+}
- if (configFiles.count() != configChecksums.count())
- throw Exception("the number of cached config files does not match the current set");
+QByteArray ConfigurationData::substituteVars(const QByteArray &sourceContent, const QString &fileName,
+ QStringList *deploymentWarnings)
+{
+ QByteArray string = sourceContent;
+ int posBeg = -1;
+ int posEnd = -1;
+ while (true) {
+ if ((posBeg = string.indexOf("${", posEnd + 1)) < 0)
+ break;
+ if ((posEnd = string.indexOf('}', posBeg + 2)) < 0)
+ break;
- for (int i = 0; i < configFiles.count(); ++i) {
- ConfigFile &cf = configFiles[i];
- if (cf.filePath != configChecksums.at(i).first)
- throw Exception("the cached config file names do not match the current set (or their order changed)");
- cf.checksum = configChecksums.at(i).second;
- }
- useCache = true;
+ const QByteArray varName = string.mid(posBeg + 2, posEnd - posBeg - 2);
-#if defined(AM_TIME_CONFIG_PARSING)
- qCDebug(LogSystem) << "Config parsing: cache loaded after" << (timer.nsecsElapsed() / 1000) << "usec";
-#endif
- } catch (const Exception &e) {
- if (deploymentWarnings)
- *deploymentWarnings << qL1S("Failed to read config cache:") + qL1S(e.what());
- }
+ QByteArray varValue;
+ if (varName == "CONFIG_PWD") {
+ static QByteArray path;
+ if (path.isEmpty() && !fileName.isEmpty())
+ path = QFileInfo(fileName).path().toUtf8();
+ varValue = path;
+ } else if (varName.startsWith("env:")) {
+ varValue = qgetenv(varName.constData() + 4);
+ } else if (varName.startsWith("stdpath:")) {
+ bool exists;
+ int loc = QMetaEnum::fromType<QStandardPaths::StandardLocation>().keyToValue(varName.constData() + 8, &exists);
+ if (exists)
+ varValue = QStandardPaths::writableLocation(static_cast<QStandardPaths::StandardLocation>(loc)).toUtf8();
}
+
+ if (varValue.isNull() && deploymentWarnings) {
+ *deploymentWarnings << qL1S("Could not replace variable ${") + qL1S(varName)
+ + qL1S("} while parsing ") + fileName;
+ continue;
+ }
+ string.replace(posBeg, varName.length() + 3, varValue);
+ // varName and varValue most likely have a different length, so we have to adjust
+ posEnd = posEnd - 3 - varName.length() + varValue.length();
}
+ return string;
+}
- // reads a single config file and calculates its hash - defined as lambda to be usable
- // both via QtConcurrent and via std:for_each
- auto readConfigFile = [&useCache, &deploymentWarnings](ConfigFile &cf) {
- QFile file(cf.filePath);
- if (!file.open(QIODevice::ReadOnly))
- throw Exception("Failed to open config file '%1' for reading.\n").arg(file.fileName());
+ConfigurationData *ConfigurationData::loadFromSource(QIODevice *source, const QString &fileName)
+{
+ try {
+ YamlParser p(source->readAll(), fileName);
+ auto header = p.parseHeader();
+ if (!(header.first == qL1S("am-configuration") && header.second == 1))
+ throw Exception("Unsupported format type and/or version");
+ p.nextDocument();
+
+ QString pwd;
+ if (!fileName.isEmpty())
+ pwd = QFileInfo(fileName).absoluteDir().path();
+
+ QScopedPointer<ConfigurationData> cd(new ConfigurationData);
+
+ YamlParser::Fields fields = {
+ { "runtimes", false, YamlParser::Map, [&cd](YamlParser *p) {
+ cd->runtimes.configurations = p->parseMap(); } },
+ { "containers", false, YamlParser::Map, [&cd](YamlParser *p) {
+ cd->containers.configurations = p->parseMap();
+
+ QVariant containerSelection = cd->containers.configurations.take(qSL("selection"));
+
+
+ QList<QPair<QString, QString>> config;
+
+ // this is easy to get wrong in the config file, so we do not just ignore a map here
+ // (this will in turn trigger the warning below)
+ if (containerSelection.type() == QVariant::Map)
+ containerSelection = QVariantList { containerSelection };
+
+ if (containerSelection.type() == QVariant::String) {
+ config.append(qMakePair(qSL("*"), containerSelection.toString()));
+ } else if (containerSelection.type() == QVariant::List) {
+ QVariantList list = containerSelection.toList();
+ for (const QVariant &v : list) {
+ if (v.type() == QVariant::Map) {
+ QVariantMap map = v.toMap();
+
+ if (map.size() != 1) {
+ qCWarning(LogSystem) << "The container selection configuration needs to be a list of "
+ "single mappings, in order to preserve the evaluation "
+ "order: found a mapping with" << map.size() << "entries.";
+ }
+
+ for (auto it = map.cbegin(); it != map.cend(); ++it)
+ config.append(qMakePair(it.key(), it.value().toString()));
+ }
+ }
+ }
+ cd->containers.selection = config;
+ } },
+ { "installationLocations", false, YamlParser::List, [&cd](YamlParser *p) {
+ cd->installationLocations = p->parseList(); } },
+ { "plugins", false, YamlParser::Map, [&cd](YamlParser *p) {
+ p->parseFields({
+ { "startup", false, YamlParser::Scalar | YamlParser::List, [&cd](YamlParser *p) {
+ cd->plugins.startup = p->parseStringOrStringList(); } },
+ { "container", false, YamlParser::Scalar | YamlParser::List, [&cd](YamlParser *p) {
+ cd->plugins.container = p->parseStringOrStringList(); } },
+ }); } },
+ { "logging", false, YamlParser::Map, [&cd](YamlParser *p) {
+ p->parseFields({
+ { "rules", false, YamlParser::Scalar | YamlParser::List, [&cd](YamlParser *p) {
+ cd->logging.rules = p->parseStringOrStringList(); } },
+ { "messagePattern", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->logging.messagePattern = p->parseScalar().toString(); } },
+ { "useAMConsoleLogger", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->logging.useAMConsoleLogger = p->parseScalar(); } },
+ { "dlt", false, YamlParser::Map, [&cd](YamlParser *p) {
+ p->parseFields( {
+ { "id", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->logging.dlt.id = p->parseScalar().toString(); } },
+ { "description", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->logging.dlt.description = p->parseScalar().toString(); } }
+ }); } }
+ }); } },
+ { "installer", false, YamlParser::Map, [&cd](YamlParser *p) {
+ p->parseFields({
+ { "disable", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->installer.disable = p->parseScalar().toBool(); } },
+ { "caCertificated", false, YamlParser::Scalar | YamlParser::List, [&cd](YamlParser *p) {
+ cd->installer.caCertificates = p->parseStringOrStringList(); } },
+ { "applicationUserIdSeparation", false, YamlParser::Map, [&cd](YamlParser *p) {
+ p->parseFields({
+ { "minUserId", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->installer.applicationUserIdSeparation.minUserId = p->parseScalar().toInt(); } },
+ { "maxUserId", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->installer.applicationUserIdSeparation.maxUserId = p->parseScalar().toInt(); } },
+ { "commonGroupId", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->installer.applicationUserIdSeparation.commonGroupId = p->parseScalar().toInt(); } }
+ }); } }
+ }); } },
+ { "quicklaunch", false, YamlParser::Map, [&cd](YamlParser *p) {
+ p->parseFields({
+ { "idleLoad", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->quicklaunch.idleLoad = p->parseScalar().toDouble(); } },
+ { "runtimesPerContainer", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->quicklaunch.runtimesPerContainer = p->parseScalar().toInt(); } },
+ }); } },
+ { "ui", false, YamlParser::Map, [&cd](YamlParser *p) {
+ p->parseFields({
+ { "enableTouchEmulation", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->ui.enableTouchEmulation = p->parseScalar().toBool(); } },
+ { "iconThemeSearchPaths", false, YamlParser::Scalar | YamlParser::List, [&cd](YamlParser *p) {
+ cd->ui.iconThemeSearchPaths = p->parseStringOrStringList(); } },
+ { "iconThemeName", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->ui.iconThemeName = p->parseScalar().toString(); } },
+ { "style", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->ui.style = p->parseScalar().toString(); } },
+ { "loadDummyData", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->ui.loadDummyData = p->parseScalar().toBool(); } },
+ { "importPaths", false, YamlParser::Scalar | YamlParser::List, [&cd](YamlParser *p) {
+ cd->ui.importPaths = p->parseStringOrStringList(); } },
+ { "pluginPaths", false, YamlParser::Scalar | YamlParser::List, [&cd](YamlParser *p) {
+ cd->ui.pluginPaths = p->parseStringOrStringList(); } },
+ { "windowIcon", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->ui.windowIcon = p->parseScalar().toString(); } },
+ { "fullscreen", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->ui.fullscreen = p->parseScalar().toBool(); } },
+ { "mainQml", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->ui.mainQml = p->parseScalar().toString(); } },
+ { "resources", false, YamlParser::Scalar | YamlParser::List, [&cd](YamlParser *p) {
+ cd->ui.resources = p->parseStringOrStringList(); } },
+ { "opengl", false, YamlParser::Map, [&cd](YamlParser *p) {
+ p->parseFields({
+ { "desktopProfile", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->ui.opengl.insert(qSL("desktopProfile"), p->parseScalar().toString()); } },
+ { "esMajorVersion", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->ui.opengl.insert(qSL("esMajorVersion"), p->parseScalar().toInt()); } },
+ { "esMinorVersion", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->ui.opengl.insert(qSL("esMinorVersion"), p->parseScalar().toInt()); } }
+ });
+ } },
+ }); } },
+ { "applications", false, YamlParser::Map, [&cd](YamlParser *p) {
+ p->parseFields({
+ { "builtinAppsManifestDir", false, YamlParser::Scalar | YamlParser::List, [&cd](YamlParser *p) {
+ cd->applications.builtinAppsManifestDir = p->parseStringOrStringList(); } },
+ { "installedAppsManifestDir", false, YamlParser::Scalar, [](YamlParser *p) {
+ (void) p->parseScalar(); /* deprecated - ignore */ } },
+ { "installationDir", false, YamlParser::Scalar | YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->applications.installationDir = p->parseScalar().toString(); } },
+ { "documentDir", false, YamlParser::Scalar | YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->applications.documentDir = p->parseScalar().toString(); } }
+ }); } },
+ { "flags", false, YamlParser::Map, [&cd](YamlParser *p) {
+ p->parseFields({
+ { "forceSingleProcess", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->flags.forceSingleProcess = p->parseScalar().toBool(); } },
+ { "forceMultiProcess", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->flags.forceMultiProcess = p->parseScalar().toBool(); } },
+ { "noSecurity", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->flags.noSecurity = p->parseScalar().toBool(); } },
+ { "developmentMode", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->flags.developmentMode = p->parseScalar().toBool(); } },
+ { "noUiWatchdog", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->flags.noUiWatchdog = p->parseScalar().toBool(); } },
+ }); } },
+ { "systemProperties", false, YamlParser::Map, [&cd](YamlParser *p) {
+ cd->systemProperties = p->parseMap(); } },
+ { "crashAction", false, YamlParser::Map, [&cd](YamlParser *p) {
+ cd->crashAction = p->parseMap(); } },
+ { "intents", false, YamlParser::Map, [&cd](YamlParser *p) {
+ p->parseFields({
+ { "disable", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->intents.disable = p->parseScalar().toBool(); } },
+ { "timeouts", false, YamlParser::Map, [&cd](YamlParser *p) {
+ p->parseFields({
+ { "disambiguation", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->intents.timeouts.disambiguation = p->parseScalar().toInt(); } },
+ { "startApplication", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->intents.timeouts.startApplication = p->parseScalar().toInt(); } },
+ { "replyFromApplication", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->intents.timeouts.replyFromApplication = p->parseScalar().toInt(); } },
+ { "replyFromSystem", false, YamlParser::Scalar, [&cd](YamlParser *p) {
+ cd->intents.timeouts.replyFromSystem = p->parseScalar().toInt(); } },
+ }); } }
+ }); } },
+ { "dbus", false, YamlParser::Map, [&cd](YamlParser *p) {
+ const QVariantMap dbus = p->parseMap();
+ for (auto it = dbus.cbegin(); it != dbus.cend(); ++it) {
+ const QString &ifaceName = it.key();
+ const QVariantMap &ifaceData = it.value().toMap();
+
+ auto rit = ifaceData.constFind(qSL("register"));
+ if (rit != ifaceData.cend())
+ cd->dbus.registrations.insert(ifaceName, rit->toString());
+
+ auto pit = ifaceData.constFind(qSL("policy"));
+ if (pit != ifaceData.cend())
+ cd->dbus.policies.insert(ifaceName, pit->toMap());
+ }
+ } }
+ };
+
+ p.parseFields(fields);
+ return cd.take();
+ } catch (const Exception &e) {
+ throw Exception(e.errorCode(), "Failed to parse config file %1: %2")
+ .arg(!fileName.isEmpty() ? QDir().relativeFilePath(fileName) : qSL("<stream>"), e.errorString());
+ }
+}
- if (file.size() > 1024*1024)
- throw Exception("Config file '%1' is too big (> 1MB).\n").arg(file.fileName());
- cf.content = substituteVars(file.readAll(), cf.filePath, deploymentWarnings);
+// getters
- QByteArray checksum = QCryptographicHash::hash(cf.content, QCryptographicHash::Sha1);
- if (useCache && (checksum != cf.checksum)) {
- if (deploymentWarnings)
- *deploymentWarnings << qL1S("Failed to read config cache: cached config file checksums do not match current set");
- useCache = false;
+static QString replaceEnvVars(QString string)
+{
+ // note: we cannot replace ${CONFIG_PWD} here, since we have lost that information during
+ // the config file merge!
+
+ static QHash<QString, QString> replacement;
+ if (replacement.isEmpty()) {
+ QMetaEnum locations = QMetaEnum::fromType<QStandardPaths::StandardLocation>();
+ for (int i = 0; i < locations.keyCount(); ++i) {
+ replacement.insert(qSL("stdpath:") + qL1S(locations.key(i)),
+ QStandardPaths::writableLocation(static_cast<QStandardPaths::StandardLocation>(locations.value(i))));
}
- cf.checksum = checksum;
- };
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ QStringList envNames = env.keys();
+ for (const auto &envName : qAsConst(envNames))
+ replacement.insert(qSL("env:") + envName, env.value(envName));
+ }
- try {
- if (configFiles.size() > AM_PARALLEL_THRESHOLD)
- QtConcurrent::blockingMap(configFiles, readConfigFile);
- else
- std::for_each(configFiles.begin(), configFiles.end(), readConfigFile);
- } catch (const Exception &e) {
- showParserMessage(e.errorString(), ErrorMessage);
- exit(1);
+ // this will return immediately, if no vars are referenced
+ int posBeg = -1;
+ int posEnd = -1;
+ while (true) {
+ if ((posBeg = string.indexOf(qL1S("${"), posEnd + 1)) < 0)
+ break;
+ if ((posEnd = string.indexOf('}', posBeg + 2)) < 0)
+ break;
+
+ const QString varName = string.mid(posBeg + 2, posEnd - posBeg - 2);
+ const QString varValue = replacement.value(varName);
+ string.replace(posBeg, varName.length() + 3, varValue);
+
+ // varName and varValue most likely have a different length, so we have to adjust
+ posEnd = posEnd - 3 - varName.length() + varValue.length();
}
+ return string;
+}
-#if defined(AM_TIME_CONFIG_PARSING)
- qCDebug(LogSystem) << "Config parsing" << configFiles.size() << "files: loading finished after"
- << (timer.nsecsElapsed() / 1000) << "usec";
-#endif
- if (useCache) {
- m_config = cache;
- } else if (!configFilePaths.isEmpty()) {
- auto parseConfigFile = [](ConfigFile &cf) {
- QtYaml::ParseError parseError;
- QVector<QVariant> docs = QtYaml::variantDocumentsFromYaml(cf.content, &parseError);
-
- if (parseError.error != QJsonParseError::NoError) {
- throw Exception("Could not parse config file '%1', line %2, column %3: %4.\n")
- .arg(cf.filePath).arg(parseError.line).arg(parseError.column)
- .arg(parseError.errorString());
- }
+QString Configuration::mainQmlFile() const
+{
+ if (!m_clp.positionalArguments().isEmpty())
+ return m_clp.positionalArguments().at(0);
+ else
+ return replaceEnvVars(m_data->ui.mainQml);
+}
- try {
- checkYamlFormat(docs, 2 /*number of expected docs*/, { "am-configuration" }, 1);
- } catch (const Exception &e) {
- throw Exception("Could not parse config file '%1': %2.\n")
- .arg(cf.filePath).arg(e.errorString());
- }
- cf.config = docs.at(1).toMap();
- };
+bool Configuration::noCache() const
+{
+ return value<bool>("no-cache");
+}
- try {
- if (configFiles.size() > AM_PARALLEL_THRESHOLD)
- QtConcurrent::blockingMap(configFiles, parseConfigFile);
- else
- std::for_each(configFiles.begin(), configFiles.end(), parseConfigFile);
- } catch (const Exception &e) {
- showParserMessage(e.errorString(), ErrorMessage);
- exit(1);
- }
+bool Configuration::clearCache() const
+{
+ return value<bool>("clear-cache");
+}
- // we cannot parallelize this step, since subsequent config files can overwrite
- // or append to values
- m_config = configFiles.at(0).config;
- for (int i = 1; i < configFiles.size(); ++i)
- mergeConfig(configFiles.at(i).config);
- if (!noConfigCache) {
- try {
- QFile cacheFile(cacheFilePath);
- if (!cacheFile.open(QFile::WriteOnly | QFile::Truncate))
- throw Exception(cacheFile, "failed to open file for writing");
+QStringList Configuration::builtinAppsManifestDirs() const
+{
+ return value<QStringList>("builtin-apps-manifest-dir", m_data->applications.builtinAppsManifestDir);
+}
- QDataStream ds(&cacheFile);
- QVector<QPair<QString, QByteArray>> configChecksums;
- for (const ConfigFile &cf : qAsConst(configFiles))
- configChecksums.append(qMakePair(cf.filePath, cf.checksum));
+QString Configuration::installationDir() const
+{
+ if (m_installationDir.isEmpty())
+ m_installationDir = value<QString>("installation-dir", m_data->applications.installationDir);
+ return m_installationDir;
+}
- ds << CacheMagicHeader << configChecksums << m_config;
+QString Configuration::documentDir() const
+{
+ if (m_documentDir.isEmpty())
+ m_documentDir = value<QString>("document-dir", m_data->applications.documentDir);
+ return m_documentDir;
+}
- if (ds.status() != QDataStream::Ok)
- throw Exception("error writing config cache content");
- } catch (const Exception &e) {
- if (deploymentWarnings)
- *deploymentWarnings << qL1S("Failed to write config cache: ") + qL1S(e.what());
- }
- }
-#if defined(AM_TIME_CONFIG_PARSING)
- qCDebug(LogSystem) << "Config parsing" << configFiles.size() << "files: parsing finished after"
- << (timer.nsecsElapsed() / 1000) << "usec";
-#endif
+bool Configuration::disableInstaller() const
+{
+ return value<bool>("disable-installer", m_data->installer.disable);
+}
+
+bool Configuration::disableIntents() const
+{
+ return value<bool>("disable-intents", m_data->intents.disable);
+}
+
+int Configuration::intentTimeoutForDisambiguation() const
+{
+ return m_data->intents.timeouts.disambiguation;
+}
+
+int Configuration::intentTimeoutForStartApplication() const
+{
+ return m_data->intents.timeouts.startApplication;
+}
+
+int Configuration::intentTimeoutForReplyFromApplication() const
+{
+ return m_data->intents.timeouts.replyFromApplication;
+}
+
+int Configuration::intentTimeoutForReplyFromSystem() const
+{
+ return m_data->intents.timeouts.replyFromSystem;
+}
+
+bool Configuration::fullscreen() const
+{
+ return value<bool>("fullscreen", m_data->ui.fullscreen);
+}
+
+bool Configuration::noFullscreen() const
+{
+ return value<bool>("no-fullscreen");
+}
+
+QString Configuration::windowIcon() const
+{
+ return m_data->ui.windowIcon;
+}
+
+QStringList Configuration::importPaths() const
+{
+ QStringList importPaths = value<QStringList>("I", m_data->ui.importPaths);
+
+ for (int i = 0; i < importPaths.size(); ++i)
+ importPaths[i] = toAbsoluteFilePath(importPaths.at(i));
+
+ return importPaths;
+}
+
+QStringList Configuration::pluginPaths() const
+{
+ return m_data->ui.pluginPaths;
+}
+
+bool Configuration::verbose() const
+{
+ return value<bool>("verbose") || m_forceVerbose;
+}
+
+void QtAM::Configuration::setForceVerbose(bool forceVerbose)
+{
+ m_forceVerbose = forceVerbose;
+}
+
+bool Configuration::slowAnimations() const
+{
+ return value<bool>("slow-animations");
+}
+
+bool Configuration::loadDummyData() const
+{
+ return value<bool>("load-dummydata", m_data->ui.loadDummyData);
+}
+
+bool Configuration::noSecurity() const
+{
+ return value<bool>("no-security", m_data->flags.noSecurity);
+}
+
+bool Configuration::developmentMode() const
+{
+ return value<bool>("development-mode", m_data->flags.developmentMode);
+}
+
+bool Configuration::noUiWatchdog() const
+{
+ return value<bool>("no-ui-watchdog", m_data->flags.noUiWatchdog);
+}
+
+bool Configuration::noDltLogging() const
+{
+ return value<bool>("no-dlt-logging");
+}
+
+bool Configuration::forceSingleProcess() const
+{
+ return value<bool>("force-single-process", m_data->flags.forceSingleProcess);
+}
+
+bool Configuration::forceMultiProcess() const
+{
+ return value<bool>("force-multi-process", m_data->flags.forceMultiProcess);
+}
+
+bool Configuration::qmlDebugging() const
+{
+ return value<bool>("qml-debug");
+}
+
+QString Configuration::singleApp() const
+{
+ //TODO: single-package
+ return value<QString>("single-app");
+}
+
+QStringList Configuration::loggingRules() const
+{
+ return value<QStringList>("logging-rule", m_data->logging.rules);
+}
+
+QString Configuration::messagePattern() const
+{
+ return m_data->logging.messagePattern;
+}
+
+QVariant Configuration::useAMConsoleLogger() const
+{
+ // true = use the am logger
+ // false = don't use the am logger
+ // invalid = don't use the am logger when QT_MESSAGE_PATTERN is set
+ const QVariant &val = m_data->logging.useAMConsoleLogger;
+ if (val.type() == QVariant::Bool)
+ return val;
+ else
+ return QVariant();
+}
+
+QString Configuration::style() const
+{
+ return m_data->ui.style;
+}
+
+QString Configuration::iconThemeName() const
+{
+ return m_data->ui.iconThemeName;
+}
+
+QStringList Configuration::iconThemeSearchPaths() const
+{
+ return m_data->ui.iconThemeSearchPaths;
+}
+
+bool Configuration::enableTouchEmulation() const
+{
+ return value("enable-touch-emulation", m_data->ui.enableTouchEmulation);
+}
+
+QString Configuration::dltId() const
+{
+ return value<QString>(nullptr, m_data->logging.dlt.id);
+}
+
+QString Configuration::dltDescription() const
+{
+ return value<QString>(nullptr, m_data->logging.dlt.description);
+}
+
+QStringList Configuration::resources() const
+{
+ return m_data->ui.resources;
+}
+
+QVariantMap Configuration::openGLConfiguration() const
+{
+ return m_data->ui.opengl;
+}
+
+QVariantList Configuration::installationLocations() const
+{
+ return m_data->installationLocations;
+}
+
+QList<QPair<QString, QString>> Configuration::containerSelectionConfiguration() const
+{
+ return m_data->containers.selection;
+}
+
+QVariantMap Configuration::containerConfigurations() const
+{
+ return m_data->containers.configurations;
+}
+
+QVariantMap Configuration::runtimeConfigurations() const
+{
+ return m_data->runtimes.configurations;
+}
+
+QVariantMap Configuration::dbusPolicy(const char *interfaceName) const
+{
+ return m_data->dbus.policies.value(qL1S(interfaceName)).toMap();
+}
+
+QString Configuration::dbusRegistration(const char *interfaceName) const
+{
+ auto hasConfig = m_data->dbus.registrations.constFind(qL1S(interfaceName));
+
+ if (hasConfig != m_data->dbus.registrations.cend())
+ return hasConfig->toString();
+ else
+ return m_clp.value(qSL("dbus"));
+}
+
+QVariantMap Configuration::rawSystemProperties() const
+{
+ return m_data->systemProperties;
+}
+
+bool Configuration::applicationUserIdSeparation(uint *minUserId, uint *maxUserId, uint *commonGroupId) const
+{
+ const auto &sep = m_data->installer.applicationUserIdSeparation;
+ if (sep.minUserId >= 0 && sep.maxUserId >= 0 && sep.commonGroupId >= 0) {
+ if (minUserId)
+ *minUserId = sep.minUserId;
+ if (maxUserId)
+ *maxUserId = sep.maxUserId;
+ if (commonGroupId)
+ *commonGroupId = sep.commonGroupId;
+ return true;
}
+ return false;
+}
- const QStringList options = m_clp.values(qSL("o"));
- for (const QString &option : options) {
- QtYaml::ParseError parseError;
- QVector<QVariant> docs = QtYaml::variantDocumentsFromYaml(option.toUtf8(), &parseError);
- if (parseError.error != QJsonParseError::NoError) {
- showParserMessage(QString::fromLatin1("Could not parse --option value, column %1: %2.\n")
- .arg(parseError.column).arg(parseError.errorString()),
- ErrorMessage);
- exit(1);
- }
- if (docs.size() != 1) {
- showParserMessage(QString::fromLatin1("Could not parse --option value: Invalid document format.\n"),
- ErrorMessage);
- exit(1);
- }
- mergeConfig(docs.at(0).toMap());
+qreal Configuration::quickLaunchIdleLoad() const
+{
+ return m_data->quicklaunch.idleLoad;
+}
+
+int Configuration::quickLaunchRuntimesPerContainer() const
+{
+ // if you need more than 10 quicklaunchers per runtime, you're probably doing something wrong
+ // or you have a typo in your YAML, which could potentially freeze your target (container
+ // construction can be expensive)
+ return qBound(0, m_data->quicklaunch.runtimesPerContainer, 10);
+}
+
+QString Configuration::waylandSocketName() const
+{
+#if !defined(AM_HEADLESS)
+ QString socketName = m_clp.value(qSL("wayland-socket-name")); // get the default value
+ if (!socketName.isEmpty())
+ return socketName;
+
+ const char *envName = "WAYLAND_DISPLAY";
+ if (qEnvironmentVariableIsSet(envName)) {
+ socketName = qEnvironmentVariable(envName);
+ if (!QGuiApplication::platformName().startsWith(qSL("wayland")) || (socketName != qSL("wayland-0")))
+ return socketName;
}
-#if defined(AM_TIME_CONFIG_PARSING)
- qCDebug(LogSystem) << "Config parsing" << options.size() << "-o options: parsing finished after"
- << (timer.nsecsElapsed() / 1000) << "usec";
+# if defined(Q_OS_LINUX)
+ // modelled after wl_socket_lock() in wayland_server.c
+ const QString xdgDir = qEnvironmentVariable("XDG_RUNTIME_DIR") + qSL("/");
+ const QString pattern = qSL("qtam-wayland-%1");
+ const QString lockSuffix = qSL(".lock");
+
+ for (int i = 0; i < 32; ++i) {
+ socketName = pattern.arg(i);
+ QFile lock(xdgDir + socketName + lockSuffix);
+ if (lock.open(QIODevice::ReadWrite)) {
+ if (::flock(lock.handle(), LOCK_EX | LOCK_NB) == 0) {
+ QFile socket(xdgDir + socketName);
+ if (!socket.exists() || socket.remove())
+ return socketName;
+ }
+ }
+ }
+# endif
#endif
+ return QString();
+
+}
- // QML cannot cope with invalid QVariants and QDataStream cannot cope with nullptr inside a
- // QVariant ... the workaround is to save invalid variants to the cache and fix them up
- // afterwards:
- fixNullValuesForQml(m_config);
+QVariantMap Configuration::managerCrashAction() const
+{
+ return m_data->crashAction;
+}
+
+QStringList Configuration::caCertificates() const
+{
+ return m_data->installer.caCertificates;
+}
+
+QStringList Configuration::pluginFilePaths(const char *type) const
+{
+ if (qstrcmp(type, "startup") == 0)
+ return m_data->plugins.startup;
+ else if (qstrcmp(type, "container") == 0)
+ return m_data->plugins.container;
+ else
+ return QStringList();
+}
+
+QStringList Configuration::testRunnerArguments() const
+{
+ QStringList targs = m_clp.positionalArguments();
+ if (!targs.isEmpty() && targs.constFirst().endsWith(qL1S(".qml")))
+ targs.removeFirst();
+ targs.prepend(QCoreApplication::arguments().constFirst());
+ return targs;
}
QT_END_NAMESPACE_AM
diff --git a/src/main-lib/configuration.h b/src/main-lib/configuration.h
index 85c91008..7c950a57 100644
--- a/src/main-lib/configuration.h
+++ b/src/main-lib/configuration.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -50,45 +51,113 @@
QT_BEGIN_NAMESPACE_AM
+struct ConfigurationData;
+
class Configuration
{
public:
+ Configuration(const QStringList &defaultConfigFilePaths, const QString &buildConfigFilePath,
+ const char *additionalDescription = nullptr, bool onlyOnePositionalArgument = true);
+ Configuration(const char *additionalDescription = nullptr, bool onlyOnePositionalArgument = true);
+
virtual ~Configuration();
void parse(QStringList *deploymentWarnings = nullptr);
virtual void parseWithArguments(const QStringList &arguments, QStringList *deploymentWarnings = nullptr);
QVariant buildConfig() const;
-protected:
- Configuration(const QStringList &defaultConfigFilePaths, const QString &buildConfigFilePath);
+ QString mainQmlFile() const;
+
+ bool noCache() const;
+ bool clearCache() const;
+
+ QStringList builtinAppsManifestDirs() const;
+ QString documentDir() const;
+ QString installationDir() const;
+ bool disableInstaller() const;
+ bool disableIntents() const;
+ int intentTimeoutForDisambiguation() const;
+ int intentTimeoutForStartApplication() const;
+ int intentTimeoutForReplyFromApplication() const;
+ int intentTimeoutForReplyFromSystem() const;
+
+ bool fullscreen() const;
+ bool noFullscreen() const;
+ QString windowIcon() const;
+ QStringList importPaths() const;
+ QStringList pluginPaths() const;
+ bool verbose() const;
+ void setForceVerbose(bool forceVerbose);
+ bool slowAnimations() const;
+ bool loadDummyData() const;
+ bool noSecurity() const;
+ bool developmentMode() const;
+ bool noUiWatchdog() const;
+ bool noDltLogging() const;
+ bool forceSingleProcess() const;
+ bool forceMultiProcess() const;
+ bool qmlDebugging() const;
+ QString singleApp() const;
+ QStringList loggingRules() const;
+ QString messagePattern() const;
+ QVariant useAMConsoleLogger() const;
+ QString style() const;
+ QString iconThemeName() const;
+ QStringList iconThemeSearchPaths() const;
+ bool enableTouchEmulation() const;
+ QString dltId() const;
+ QString dltDescription() const;
+ QStringList resources() const;
+
+ QVariantMap openGLConfiguration() const;
+
+ QVariantList installationLocations() const;
+
+ QList<QPair<QString, QString>> containerSelectionConfiguration() const;
+ QVariantMap containerConfigurations() const;
+ QVariantMap runtimeConfigurations() const;
+
+ QVariantMap dbusPolicy(const char *interfaceName) const;
+ QString dbusRegistration(const char *interfaceName) const;
+
+ QVariantMap rawSystemProperties() const;
+
+ bool applicationUserIdSeparation(uint *minUserId, uint *maxUserId, uint *commonGroupId) const;
+ qreal quickLaunchIdleLoad() const;
+ int quickLaunchRuntimesPerContainer() const;
+
+ QString waylandSocketName() const;
+
+ QVariantMap managerCrashAction() const;
+
+ QStringList caCertificates() const;
+
+ QStringList pluginFilePaths(const char *type) const;
+
+ QStringList testRunnerArguments() const;
+
+private:
enum MessageType { UsageMessage, ErrorMessage };
void showParserMessage(const QString &message, MessageType type);
- template <typename T> T value(const char *clname, const QVector<const char *> &cfname = QVector<const char *>()) const
+ template <typename T> T value(const char *clname, const T &cfvalue = T()) const
{
Q_UNUSED(clname)
- Q_UNUSED(cfname)
+ Q_UNUSED(cfvalue)
return T();
}
-private:
- QVariant findInConfigFile(const QVector<const char *> &path, bool *found = nullptr) const;
- void mergeConfig(const QVariantMap &other);
- static QByteArray substituteVars(const QByteArray &str, const QString &fileName,
- QStringList *deploymentWarnings = nullptr);
-
-protected:
QStringList m_defaultConfigFilePaths;
QString m_buildConfigFilePath;
QCommandLineParser m_clp;
- QVariantMap m_config;
+ ConfigurationData *m_data;
+ QString m_mainQmlFile;
+ bool m_onlyOnePositionalArgument = false;
+ bool m_forceVerbose = false;
+ mutable QString m_installationDir; // cached value
+ mutable QString m_documentDir; // cached value
};
-template<> bool Configuration::value(const char *clname, const QVector<const char *> &cfname) const;
-template<> QString Configuration::value(const char *clname, const QVector<const char *> &cfname) const;
-template<> QStringList Configuration::value(const char *clname, const QVector<const char *> &cfname) const;
-template<> QVariant Configuration::value(const char *clname, const QVector<const char *> &cfname) const;
-
QT_END_NAMESPACE_AM
diff --git a/src/main-lib/configuration_p.h b/src/main-lib/configuration_p.h
new file mode 100644
index 00000000..e97f9f2f
--- /dev/null
+++ b/src/main-lib/configuration_p.h
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtAppManCommon/global.h>
+#include <QStringList>
+#include <QVariantMap>
+#include <QVector>
+#include <QSet>
+
+QT_FORWARD_DECLARE_CLASS(QIODevice)
+
+QT_BEGIN_NAMESPACE_AM
+
+
+// IMPORTANT: if you add/remove/change anything in this struct, you also have to adjust the
+// loadFromCache(), saveToCache() and mergeFrom() functions in the cpp file!
+
+struct ConfigurationData
+{
+ static ConfigurationData *loadFromSource(QIODevice *source, const QString &fileName);
+ static QByteArray substituteVars(const QByteArray &sourceContent, const QString &fileName,
+ QStringList *deploymentWarnings = nullptr);
+ static ConfigurationData *loadFromCache(QDataStream &ds);
+ void saveToCache(QDataStream &ds) const;
+ void mergeFrom(const ConfigurationData *from);
+
+
+ struct Runtimes {
+ QVariantMap configurations;
+ } runtimes;
+
+ struct {
+ QVariantMap configurations;
+ QList<QPair<QString, QString>> selection;
+ } containers;
+
+ struct {
+ bool disable = false;
+ struct {
+ int disambiguation = 10000;
+ int startApplication = 3000;
+ int replyFromApplication = 5000;
+ int replyFromSystem = 20000;
+ } timeouts;
+ } intents;
+
+ struct {
+ QStringList startup;
+ QStringList container;
+ } plugins;
+
+ struct {
+ struct {
+ QString id;
+ QString description;
+ } dlt;
+ QStringList rules;
+ QString messagePattern;
+ QVariant useAMConsoleLogger; // true / false / invalid
+ } logging;
+
+ struct {
+ bool disable = false;
+ QStringList caCertificates;
+ struct {
+ int minUserId = -1;
+ int maxUserId = -1;
+ int commonGroupId = -1;
+ } applicationUserIdSeparation;
+ } installer;
+
+ struct {
+ QVariantMap policies;
+ QVariantMap registrations;
+ } dbus;
+
+ struct {
+ double idleLoad = 0.;
+ int runtimesPerContainer = 0;
+ } quicklaunch;
+
+ struct {
+ QVariantMap opengl;
+ bool enableTouchEmulation = false;
+ QStringList iconThemeSearchPaths;
+ QString iconThemeName;
+ QString style;
+ bool loadDummyData = false;
+ QStringList importPaths;
+ QStringList pluginPaths;
+ QString windowIcon;
+ bool fullscreen = false;
+ QString mainQml;
+ QStringList resources;
+ } ui;
+
+ struct {
+ QStringList builtinAppsManifestDir;
+ QString installationDir;
+ QString documentDir;
+ } applications; // TODO: rename to package?
+
+ QVariantList installationLocations;
+
+ QVariantMap crashAction;
+ QVariantMap systemProperties;
+
+ struct {
+ bool forceSingleProcess = false;
+ bool forceMultiProcess = false;
+ bool noSecurity = false;
+ bool developmentMode = false;
+ bool noUiWatchdog = false;
+ } flags;
+
+ // command-line only:
+ struct {
+ QString waylandSocketName;
+ bool noFullscreen = false;
+ bool verbose = false;
+ bool slowAnimations = false;
+ bool noDltLogging = false;
+ bool singlePackage = false;
+ bool qmlDebug = false;
+ bool touchEmulation = false;
+ } commandLine;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/main-lib/defaultconfiguration.cpp b/src/main-lib/defaultconfiguration.cpp
index 01ef4b13..f83ec52a 100644
--- a/src/main-lib/defaultconfiguration.cpp
+++ b/src/main-lib/defaultconfiguration.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -40,503 +41,3 @@
**
****************************************************************************/
-#include <QFileInfo>
-#include <QCoreApplication>
-#include <QFile>
-#include <QDebug>
-
-#if defined(Q_OS_LINUX)
-# include <sys/file.h>
-#endif
-
-#if !defined(AM_HEADLESS)
-# include <QGuiApplication>
-#endif
-
-#include <QtAppManCommon/logging.h>
-
-#include "defaultconfiguration.h"
-
-QT_BEGIN_NAMESPACE_AM
-
-
-DefaultConfiguration::DefaultConfiguration(const char *additionalDescription,
- bool onlyOnePositionalArgument)
- : DefaultConfiguration(QStringList(), qSL(":/build-config.yaml"),
- additionalDescription, onlyOnePositionalArgument)
-{ }
-
-DefaultConfiguration::DefaultConfiguration(const QStringList &defaultConfigFilePaths,
- const QString &buildConfigFilePath,
- const char *additionalDescription,
- bool onlyOnePositionalArgument)
- : Configuration(defaultConfigFilePaths, buildConfigFilePath)
- , m_onlyOnePositionalArgument(onlyOnePositionalArgument)
-{
- // using QStringLiteral for all strings here adds a few KB of ro-data, but will also improve
- // startup times slightly: less allocations and copies. MSVC cannot cope with multi-line though
-
- const char *description =
- "In addition to the commandline options below, the following environment\n"
- "variables can be set:\n\n"
- " AM_STARTUP_TIMER if set to 1, a startup performance analysis will be printed\n"
- " on the console. Anything other than 1 will be interpreted\n"
- " as the name of a file that is used instead of the console.\n"
- "\n"
- " AM_FORCE_COLOR_OUTPUT can be set to 'on' to force color output to the console\n"
- " and to 'off' to disable it. Any other value will result\n"
- " in the default, auto-detection behavior.\n";
-
- m_clp.setApplicationDescription(qSL("\n") + QCoreApplication::applicationName() + qSL("\n\n")
- + (additionalDescription ? (qL1S(additionalDescription) + qSL("\n\n")) : QString())
- + qL1S(description));
-
- m_clp.addPositionalArgument(qSL("qml-file"), qSL("the main QML file."));
- m_clp.addOption({ qSL("database"), qSL("filepath of the application database cache."), qSL("file") });
- m_clp.addOption({ { qSL("r"), qSL("recreate-database") }, qSL("recreate the application database cache.") });
- m_clp.addOption({ qSL("builtin-apps-manifest-dir"), qSL("base directory for built-in application manifests."), qSL("dir") });
- m_clp.addOption({ qSL("installed-apps-manifest-dir"), qSL("base directory for installed application manifests."), qSL("dir") });
- m_clp.addOption({ qSL("app-image-mount-dir"), qSL("deprecated, not needed anymore."), qSL("dir") });
- m_clp.addOption({ qSL("disable-installer"), qSL("disable the application installer sub-system.") });
- m_clp.addOption({ qSL("disable-intents"), qSL("disable the intents sub-system.") });
-#if defined(QT_DBUS_LIB)
- m_clp.addOption({ qSL("dbus"), qSL("register on the specified D-Bus."), qSL("<bus>|system|session|none|auto"), qSL("auto") });
- m_clp.addOption({ qSL("start-session-dbus"), qSL("deprecated (ignored).") });
-#endif
- m_clp.addOption({ qSL("fullscreen"), qSL("display in full-screen.") });
- m_clp.addOption({ qSL("no-fullscreen"), qSL("do not display in full-screen.") });
- m_clp.addOption({ qSL("I"), qSL("additional QML import path."), qSL("dir") });
- m_clp.addOption({ qSL("verbose"), qSL("verbose output.") });
- m_clp.addOption({ qSL("slow-animations"), qSL("run all animations in slow motion.") });
- m_clp.addOption({ qSL("load-dummydata"), qSL("loads QML dummy-data.") });
- m_clp.addOption({ qSL("no-security"), qSL("disables all security related checks (dev only!)") });
- m_clp.addOption({ qSL("development-mode"), qSL("enable development mode, allowing installation of dev-signed packages.") });
- m_clp.addOption({ qSL("no-ui-watchdog"), qSL("disables detecting hung UI applications (e.g. via Wayland's ping/pong).") });
- m_clp.addOption({ qSL("no-dlt-logging"), qSL("disables logging using automotive DLT.") });
- m_clp.addOption({ qSL("force-single-process"), qSL("forces single-process mode even on a wayland enabled build.") });
- m_clp.addOption({ qSL("force-multi-process"), qSL("forces multi-process mode. Will exit immediately if this is not possible.") });
- m_clp.addOption({ qSL("wayland-socket-name"), qSL("use this file name to create the wayland socket."), qSL("socket") });
- m_clp.addOption({ qSL("single-app"), qSL("runs a single application only (ignores the database)"), qSL("info.yaml file") });
- m_clp.addOption({ qSL("logging-rule"), qSL("adds a standard Qt logging rule."), qSL("rule") });
- m_clp.addOption({ qSL("qml-debug"), qSL("enables QML debugging and profiling.") });
- m_clp.addOption({ qSL("enable-touch-emulation"), qSL("enables the touch emulation, converting mouse to touch events.") });
-}
-
-DefaultConfiguration::~DefaultConfiguration()
-{
-}
-
-
-void DefaultConfiguration::parseWithArguments(const QStringList &arguments, QStringList *deploymentWarnings)
-{
- Configuration::parseWithArguments(arguments, deploymentWarnings);
-
- if (m_onlyOnePositionalArgument && (m_clp.positionalArguments().size() > 1)) {
- showParserMessage(qL1S("Only one main qml file can be specified.\n"), ErrorMessage);
- exit(1);
- }
-
- if (!deploymentWarnings)
- return;
-
- if (database().isEmpty())
- *deploymentWarnings << qL1S("No --database command line parameter or applications/database configuration"
- " key specified. Database won't be cached to speed up subsequent System-UI startups.");
-
- if (installedAppsManifestDir().isEmpty())
- *deploymentWarnings << qL1S("No --installed-apps-manifest-dir command line parameter or"
- " applications/installedAppsManifestDir configuration key specified. It won't be possible to install,"
- " remove or access installable applications.");
-
- if (value<bool>("start-session-dbus"))
- *deploymentWarnings << qL1S("Option \"--start-session-dbus\" has been deprecated and will be ignored.");
-}
-
-QString DefaultConfiguration::mainQmlFile() const
-{
- if (!m_clp.positionalArguments().isEmpty() && m_clp.positionalArguments().at(0).endsWith(qL1S(".qml")))
- return m_clp.positionalArguments().at(0);
- else
- return value<QString>(nullptr, { "ui", "mainQml" });
-}
-
-
-QString DefaultConfiguration::database() const
-{
- return value<QString>("database", { "applications", "database" });
-}
-
-bool DefaultConfiguration::recreateDatabase() const
-{
- return value<bool>("recreate-database");
-}
-
-QStringList DefaultConfiguration::builtinAppsManifestDirs() const
-{
- return value<QStringList>("builtin-apps-manifest-dir", { "applications", "builtinAppsManifestDir" });
-}
-
-QString DefaultConfiguration::installedAppsManifestDir() const
-{
- return value<QString>("installed-apps-manifest-dir", { "applications", "installedAppsManifestDir" });
-}
-
-bool DefaultConfiguration::disableInstaller() const
-{
- return value<bool>("disable-installer", { "installer", "disable" });
-}
-
-bool DefaultConfiguration::disableIntents() const
-{
- return value<bool>("disable-intents", { "intents", "disable" });
-}
-
-QMap<QString, int> DefaultConfiguration::intentTimeouts() const
-{
- QVariantMap map = value<QVariant>(nullptr, { "intents", "timeouts" }).toMap();
- QMap<QString, int> timeouts;
-
- for (auto it = map.cbegin(); it != map.cend(); ++it) {
- QVariant v = it.value();
- if (v.canConvert<int>())
- timeouts.insert(it.key(), v.toInt());
- }
- return timeouts;
-}
-
-
-bool DefaultConfiguration::fullscreen() const
-{
- return value<bool>("fullscreen", { "ui", "fullscreen" });
-}
-
-bool DefaultConfiguration::noFullscreen() const
-{
- return value<bool>("no-fullscreen");
-}
-
-QString DefaultConfiguration::windowIcon() const
-{
- return value<QString>(nullptr, { "ui", "windowIcon" });
-}
-
-QStringList DefaultConfiguration::importPaths() const
-{
- QStringList importPaths = value<QStringList>("I", { "ui", "importPaths" });
-
- for (int i = 0; i < importPaths.size(); ++i)
- importPaths[i] = QFileInfo(importPaths.at(i)).absoluteFilePath();
-
- return importPaths;
-}
-
-QStringList DefaultConfiguration::pluginPaths() const
-{
- QStringList pluginPaths = value<QStringList>(nullptr, { "ui", "pluginPaths" });
-
- for (int i = 0; i < pluginPaths.size(); ++i)
- pluginPaths[i] = QFileInfo(pluginPaths.at(i)).absoluteFilePath();
-
- return pluginPaths;
-}
-
-bool DefaultConfiguration::verbose() const
-{
- return value<bool>("verbose") || m_forceVerbose;
-}
-
-void QtAM::DefaultConfiguration::setForceVerbose(bool forceVerbose)
-{
- m_forceVerbose = forceVerbose;
-}
-
-bool DefaultConfiguration::slowAnimations() const
-{
- return value<bool>("slow-animations");
-}
-
-bool DefaultConfiguration::loadDummyData() const
-{
- return value<bool>("load-dummydata", { "ui", "loadDummyData" });
-}
-
-bool DefaultConfiguration::noSecurity() const
-{
- return value<bool>("no-security", { "flags", "noSecurity" });
-}
-
-bool DefaultConfiguration::developmentMode() const
-{
- return value<bool>("development-mode", { "flags", "developmentMode" });
-}
-
-bool DefaultConfiguration::noUiWatchdog() const
-{
- return value<bool>("no-ui-watchdog", { "flags", "noUiWatchdog" });
-}
-
-bool DefaultConfiguration::noDltLogging() const
-{
- return value<bool>("no-dlt-logging");
-}
-
-bool DefaultConfiguration::forceSingleProcess() const
-{
- return value<bool>("force-single-process", { "flags", "forceSingleProcess" });
-}
-
-bool DefaultConfiguration::forceMultiProcess() const
-{
- return value<bool>("force-multi-process", { "flags", "forceMultiProcess" });
-}
-
-bool DefaultConfiguration::qmlDebugging() const
-{
- return value<bool>("qml-debug");
-}
-
-QString DefaultConfiguration::singleApp() const
-{
- return value<QString>("single-app");
-}
-
-QStringList DefaultConfiguration::loggingRules() const
-{
- return value<QStringList>("logging-rule", { "logging", "rules" });
-}
-
-QString DefaultConfiguration::messagePattern() const
-{
- return value<QString>(nullptr, { "logging", "messagePattern" });
-}
-
-QVariant DefaultConfiguration::useAMConsoleLogger() const
-{
- // true = use the am logger
- // false = don't use the am logger
- // invalid = don't use the am logger when QT_MESSAGE_PATTERN is set
- QVariant val = value<QVariant>(nullptr, { "logging", "useAMConsoleLogger" });
- if (val.type() == QVariant::Bool)
- return val;
- else
- return QVariant();
-}
-
-QString DefaultConfiguration::style() const
-{
- return value<QString>(nullptr, { "ui", "style" });
-}
-
-QString DefaultConfiguration::iconThemeName() const
-{
- return value<QString>(nullptr, { "ui", "iconThemeName" });
-}
-
-QStringList DefaultConfiguration::iconThemeSearchPaths() const
-{
- return value<QStringList>(nullptr, { "ui", "iconThemeSearchPaths" });
-}
-
-bool DefaultConfiguration::enableTouchEmulation() const
-{
- return value<bool>("enable-touch-emulation", { "ui", "enableTouchEmulation" });
-}
-
-QString DefaultConfiguration::dltId() const
-{
- return value<QString>(nullptr, { "logging", "dlt", "id" });
-}
-
-QString DefaultConfiguration::dltDescription() const
-{
- return value<QString>(nullptr, { "logging", "dlt", "description" });
-}
-
-QVariantMap DefaultConfiguration::openGLConfiguration() const
-{
- return value<QVariant>(nullptr, { "ui", "opengl" }).toMap();
-}
-
-QVariantList DefaultConfiguration::installationLocations() const
-{
- return value<QVariant>(nullptr, { "installationLocations" }).toList();
-}
-
-QList<QPair<QString, QString>> DefaultConfiguration::containerSelectionConfiguration() const
-{
- QList<QPair<QString, QString>> config;
- QVariant containerSelection = value<QVariant>(nullptr, { "containers", "selection" });
-
- // this is easy to get wrong in the config file, so we do not just ignore a map here
- // (this will in turn trigger the warning below)
- if (containerSelection.type() == QVariant::Map)
- containerSelection = QVariantList { containerSelection };
-
- if (containerSelection.type() == QVariant::String) {
- config.append(qMakePair(qSL("*"), containerSelection.toString()));
- } else if (containerSelection.type() == QVariant::List) {
- QVariantList list = containerSelection.toList();
- for (const QVariant &v : list) {
- if (v.type() == QVariant::Map) {
- QVariantMap map = v.toMap();
-
- if (map.size() != 1) {
- qCWarning(LogSystem) << "The container selection configuration needs to be a list of "
- "single mappings, in order to preserve the evaluation "
- "order: found a mapping with" << map.size() << "entries.";
- }
-
- for (auto it = map.cbegin(); it != map.cend(); ++it)
- config.append(qMakePair(it.key(), it.value().toString()));
- }
- }
- }
- return config;
-}
-
-QVariantMap DefaultConfiguration::containerConfigurations() const
-{
- QVariantMap map = value<QVariant>(nullptr, { "containers" }).toMap();
- map.remove(qSL("selection"));
- return map;
-}
-
-QVariantMap DefaultConfiguration::runtimeConfigurations() const
-{
- return value<QVariant>(nullptr, { "runtimes" }).toMap();
-}
-
-QVariantMap DefaultConfiguration::dbusPolicy(const char *interfaceName) const
-{
- return value<QVariant>(nullptr, { "dbus", interfaceName, "policy" }).toMap();
-}
-
-QString DefaultConfiguration::dbusRegistration(const char *interfaceName) const
-{
- return value<QString>("dbus", { "dbus", interfaceName, "register" });
-}
-
-QVariantMap DefaultConfiguration::rawSystemProperties() const
-{
- return value<QVariant>(nullptr, { "systemProperties" }).toMap();
-}
-
-bool DefaultConfiguration::applicationUserIdSeparation(uint *minUserId, uint *maxUserId, uint *commonGroupId) const
-{
- bool found = false;
- QVariantMap map = value<QVariant>(nullptr, { "installer", "applicationUserIdSeparation" }).toMap();
-
- if (found) {
- auto idFromMap = [&map](const char *key) -> uint {
- bool ok;
- uint value = map.value(qL1S(key)).toUInt(&ok);
- return ok ? value : uint(-1);
- };
-
- uint undef = uint(-1);
- uint minUser = idFromMap("minUserId");
- uint maxUser = idFromMap("maxUserId");
- uint commonGroup = idFromMap("commonGroupId");
-
- if (minUser != undef && maxUser != undef && commonGroup != undef && minUser < maxUser) {
- if (minUserId)
- *minUserId = minUser;
- if (maxUserId)
- *maxUserId = maxUser;
- if (commonGroupId)
- *commonGroupId = commonGroup;
- return true;
- }
- }
- return false;
-}
-
-qreal DefaultConfiguration::quickLaunchIdleLoad() const
-{
- return value<QVariant>(nullptr, { "quicklaunch", "idleLoad" }).toReal();
-}
-
-int DefaultConfiguration::quickLaunchRuntimesPerContainer() const
-{
- int rpc = value<QVariant>(nullptr, { "quicklaunch", "runtimesPerContainer" }).toInt();
-
- // if you need more than 10 quicklaunchers per runtime, you're probably doing something wrong
- // or you have a typo in your YAML, which could potentially freeze your target (container
- // construction can be expensive)
- return qBound(0, rpc, 10);
-}
-
-QString DefaultConfiguration::waylandSocketName() const
-{
-#if !defined(AM_HEADLESS)
- QString socketName = m_clp.value(qSL("wayland-socket-name")); // get the default value
- if (!socketName.isEmpty())
- return socketName;
-
- const char *envName = "WAYLAND_DISPLAY";
- if (qEnvironmentVariableIsSet(envName)) {
- socketName = qEnvironmentVariable(envName);
- if (!QGuiApplication::platformName().startsWith(qSL("wayland")) || (socketName != qSL("wayland-0")))
- return socketName;
- }
-
-# if defined(Q_OS_LINUX)
- // modelled after wl_socket_lock() in wayland_server.c
- const QString xdgDir = qEnvironmentVariable("XDG_RUNTIME_DIR") + qSL("/");
- const QString pattern = qSL("qtam-wayland-%1");
- const QString lockSuffix = qSL(".lock");
-
- for (int i = 0; i < 32; ++i) {
- socketName = pattern.arg(i);
- QFile lock(xdgDir + socketName + lockSuffix);
- if (lock.open(QIODevice::ReadWrite)) {
- if (::flock(lock.handle(), LOCK_EX | LOCK_NB) == 0) {
- QFile socket(xdgDir + socketName);
- if (!socket.exists() || socket.remove())
- return socketName;
- }
- }
- }
-# endif
-#endif
- return QString();
-}
-
-QString DefaultConfiguration::telnetAddress() const
-{
- QString s = value<QString>(nullptr, { "debug", "telnetAddress" });
- if (s.isEmpty())
- s = qSL("0.0.0.0");
- return s;
-}
-
-quint16 DefaultConfiguration::telnetPort() const
-{
- return value<QVariant>(nullptr, { "debug", "telnetPort" }).value<quint16>();
-}
-
-QVariantMap DefaultConfiguration::managerCrashAction() const
-{
- return value<QVariant>(nullptr, { "crashAction"} ).toMap();
-}
-
-QStringList DefaultConfiguration::caCertificates() const
-{
- return value<QStringList>(nullptr, { "installer", "caCertificates" });
-}
-
-QStringList DefaultConfiguration::pluginFilePaths(const char *type) const
-{
- return value<QStringList>(nullptr, { "plugins", type });
-}
-
-QStringList DefaultConfiguration::testRunnerArguments() const
-{
- QStringList targs = m_clp.positionalArguments();
- if (!targs.isEmpty() && targs.constFirst().endsWith(qL1S(".qml")))
- targs.removeFirst();
- targs.prepend(QCoreApplication::arguments().constFirst());
- return targs;
-}
-
-QT_END_NAMESPACE_AM
diff --git a/src/main-lib/defaultconfiguration.h b/src/main-lib/defaultconfiguration.h
index d61abdcc..2245ae2d 100644
--- a/src/main-lib/defaultconfiguration.h
+++ b/src/main-lib/defaultconfiguration.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -47,91 +48,6 @@
QT_BEGIN_NAMESPACE_AM
-class DefaultConfiguration : public Configuration
-{
-public:
- DefaultConfiguration(const char *additionalDescription = nullptr,
- bool onlyOnePositionalArgument = true);
- DefaultConfiguration(const QStringList &defaultConfigFilePaths,
- const QString &buildConfigFilePath,
- const char *additionalDescription = nullptr,
- bool onlyOnePositionalArgument = true);
- ~DefaultConfiguration() override;
-
- void parseWithArguments(const QStringList &arguments, QStringList *deploymentWarnings = nullptr) override;
-
- QString mainQmlFile() const;
- QString database() const;
- bool recreateDatabase() const;
-
- QStringList builtinAppsManifestDirs() const;
- QString installedAppsManifestDir() const;
- bool disableInstaller() const;
- bool disableIntents() const;
- QMap<QString, int> intentTimeouts() const;
-
- bool fullscreen() const;
- bool noFullscreen() const;
- QString windowIcon() const;
- QStringList importPaths() const;
- QStringList pluginPaths() const;
- bool verbose() const;
- void setForceVerbose(bool forceVerbose);
- bool slowAnimations() const;
- bool loadDummyData() const;
- bool noSecurity() const;
- bool developmentMode() const;
- bool noUiWatchdog() const;
- bool noDltLogging() const;
- bool forceSingleProcess() const;
- bool forceMultiProcess() const;
- bool qmlDebugging() const;
- QString singleApp() const;
- QStringList loggingRules() const;
- QString messagePattern() const;
- QVariant useAMConsoleLogger() const;
- QString style() const;
- QString iconThemeName() const;
- QStringList iconThemeSearchPaths() const;
- bool enableTouchEmulation() const;
- QString dltId() const;
- QString dltDescription() const;
-
- QVariantMap openGLConfiguration() const;
-
- QVariantList installationLocations() const;
-
- QList<QPair<QString, QString>> containerSelectionConfiguration() const;
- QVariantMap containerConfigurations() const;
- QVariantMap runtimeConfigurations() const;
-
- QVariantMap dbusPolicy(const char *interfaceName) const;
- QString dbusRegistration(const char *interfaceName) const;
-
- QVariantMap rawSystemProperties() const;
-
- bool applicationUserIdSeparation(uint *minUserId, uint *maxUserId, uint *commonGroupId) const;
-
- qreal quickLaunchIdleLoad() const;
- int quickLaunchRuntimesPerContainer() const;
-
- QString waylandSocketName() const;
-
- QString telnetAddress() const;
- quint16 telnetPort() const;
-
- QVariantMap managerCrashAction() const;
-
- QStringList caCertificates() const;
-
- QStringList pluginFilePaths(const char *type) const;
-
- QStringList testRunnerArguments() const;
-
-private:
- QString m_mainQmlFile;
- bool m_onlyOnePositionalArgument = false;
- bool m_forceVerbose = false;
-};
+using DefaultConfiguration = Configuration;
QT_END_NAMESPACE_AM
diff --git a/src/main-lib/main-lib.pro b/src/main-lib/main-lib.pro
index 73a972c3..052b57df 100644
--- a/src/main-lib/main-lib.pro
+++ b/src/main-lib/main-lib.pro
@@ -14,7 +14,6 @@ QT *= \
appman_application-private \
appman_manager-private \
appman_package-private \
- appman_installer-private \
appman_notification-private \
appman_monitor-private \
appman_shared_main-private \
@@ -33,7 +32,9 @@ DEFINES += AM_BUILD_DIR=\\\"$$BUILD_DIR\\\"
HEADERS += \
configuration.h \
main.h \
+ configuration_p.h \
defaultconfiguration.h \
+ applicationinstaller.h \
!headless:HEADERS += \
windowframetimer.h \
@@ -42,6 +43,7 @@ SOURCES += \
main.cpp \
configuration.cpp \
defaultconfiguration.cpp \
+ applicationinstaller.cpp \
!headless:SOURCES += \
windowframetimer.cpp \
diff --git a/src/main-lib/main.cpp b/src/main-lib/main.cpp
index 9c493a7b..ffd17dda 100644
--- a/src/main-lib/main.cpp
+++ b/src/main-lib/main.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -49,7 +50,7 @@
# include "dbusdaemon.h"
# include "dbuspolicy.h"
# include "applicationmanagerdbuscontextadaptor.h"
-# include "applicationinstallerdbuscontextadaptor.h"
+# include "packagemanagerdbuscontextadaptor.h"
# include "notificationmanagerdbuscontextadaptor.h"
#endif
@@ -93,15 +94,16 @@
#include "global.h"
#include "logging.h"
#include "main.h"
-#include "defaultconfiguration.h"
-#include "applicationinfo.h"
+#include "configuration.h"
#include "applicationmanager.h"
-#include "applicationdatabase.h"
+#include "packagemanager.h"
+#include "packagedatabase.h"
#include "installationreport.h"
-#include "yamlapplicationscanner.h"
+#include "yamlpackagescanner.h"
#if !defined(AM_DISABLE_INSTALLER)
# include "applicationinstaller.h"
# include "sudo.h"
+# include "packageutilities.h"
#endif
#include "runtimefactory.h"
#include "containerfactory.h"
@@ -116,7 +118,6 @@
#include "qmlinprocessapplicationinterface.h"
#include "qml-utilities.h"
#include "dbus-utilities.h"
-#include "package.h"
#include "intentserver.h"
#include "intentaminterface.h"
@@ -186,6 +187,10 @@ Main::~Main()
delete m_view;
# endif
delete m_applicationManager;
+#if !defined(AM_DISABLE_INSTALLER)
+ delete m_applicationInstaller;
+#endif
+ delete m_packageManager;
delete m_quickLauncher;
delete m_applicationIPCManager;
@@ -198,13 +203,14 @@ Main::~Main()
The caller has to make sure that cfg will be available even after this function returns:
we will access the cfg object from delayed init functions via lambdas!
*/
-void Main::setup(const DefaultConfiguration *cfg, const QStringList &deploymentWarnings) Q_DECL_NOEXCEPT_EXPR(false)
+void Main::setup(const Configuration *cfg, const QStringList &deploymentWarnings) Q_DECL_NOEXCEPT_EXPR(false)
{
// basics that are needed in multiple setup functions below
m_noSecurity = cfg->noSecurity();
m_developmentMode = cfg->developmentMode();
m_builtinAppsManifestDirs = cfg->builtinAppsManifestDirs();
- m_installedAppsManifestDir = cfg->installedAppsManifestDir();
+ m_installationDir = cfg->installationDir();
+ m_documentDir = cfg->documentDir();
CrashHandler::setCrashActionConfiguration(cfg->managerCrashAction());
setupLogging(cfg->verbose(), cfg->loggingRules(), cfg->messagePattern(), cfg->useAMConsoleLogger());
@@ -217,6 +223,8 @@ void Main::setup(const DefaultConfiguration *cfg, const QStringList &deploymentW
for (const QString &warning : deploymentWarnings)
qCWarning(LogDeployment).noquote() << warning;
+ registerResources(cfg->resources());
+
setupOpenGL(cfg->openGLConfiguration());
setupIconTheme(cfg->iconThemeSearchPaths(), cfg->iconThemeName());
@@ -228,35 +236,36 @@ void Main::setup(const DefaultConfiguration *cfg, const QStringList &deploymentW
setupRuntimesAndContainers(cfg->runtimeConfigurations(), cfg->openGLConfiguration(),
cfg->containerConfigurations(), cfg->pluginFilePaths("container"),
cfg->iconThemeSearchPaths(), cfg->iconThemeName());
- if (!cfg->disableInstaller())
- setupInstallationLocations(cfg->installationLocations());
- if (!cfg->database().isEmpty())
- loadApplicationDatabase(cfg->database(), cfg->recreateDatabase(), cfg->singleApp());
+ loadPackageDatabase(cfg->clearCache() || cfg->noCache(), cfg->singleApp());
setupSingletons(cfg->containerSelectionConfiguration(), cfg->quickLaunchRuntimesPerContainer(),
- cfg->quickLaunchIdleLoad(), cfg->singleApp());
+ cfg->quickLaunchIdleLoad());
+
+ if (!cfg->disableIntents()) {
+ setupIntents(cfg->intentTimeoutForDisambiguation(), cfg->intentTimeoutForStartApplication(),
+ cfg->intentTimeoutForReplyFromApplication(), cfg->intentTimeoutForReplyFromSystem());
+ }
- if (m_installedAppsManifestDir.isEmpty() || cfg->disableInstaller()) {
+ registerPackages();
+
+ if (m_installationDir.isEmpty() || cfg->disableInstaller()) {
StartupTimer::instance()->checkpoint("skipping installer");
} else {
setupInstaller(cfg->caCertificates(),
- std::bind(&DefaultConfiguration::applicationUserIdSeparation, cfg,
+ std::bind(&Configuration::applicationUserIdSeparation, cfg,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
}
- if (!cfg->disableIntents())
- setupIntents(cfg->intentTimeouts());
-
setLibraryPaths(libraryPaths() + cfg->pluginPaths());
setupQmlEngine(cfg->importPaths(), cfg->style());
setupWindowTitle(QString(), cfg->windowIcon());
setupWindowManager(cfg->waylandSocketName(), cfg->slowAnimations(), cfg->noUiWatchdog());
setupTouchEmulation(cfg->enableTouchEmulation());
- setupShellServer(cfg->telnetAddress(), cfg->telnetPort());
+ setupShellServer(QString(), 0); // remove
setupSSDPService();
- setupDBus(std::bind(&DefaultConfiguration::dbusRegistration, cfg, std::placeholders::_1),
- std::bind(&DefaultConfiguration::dbusPolicy, cfg, std::placeholders::_1));
+ setupDBus(std::bind(&Configuration::dbusRegistration, cfg, std::placeholders::_1),
+ std::bind(&Configuration::dbusPolicy, cfg, std::placeholders::_1));
}
bool Main::isSingleProcessMode() const
@@ -321,6 +330,14 @@ QQmlApplicationEngine *Main::qmlEngine() const
return m_engine;
}
+void Main::registerResources(const QStringList &resources) const
+{
+ for (const QString &resource: resources) {
+ if (!loadResource(resource))
+ qCWarning(LogSystem) << "Cannot register resource:" << resource;
+ }
+}
+
void Main::loadStartupPlugins(const QStringList &startupPluginPaths) Q_DECL_NOEXCEPT_EXPR(false)
{
m_startupPlugins = loadPlugins<StartupInterface>("startup", startupPluginPaths);
@@ -350,21 +367,20 @@ void Main::parseSystemProperties(const QVariantMap &rawSystemProperties)
void Main::setMainQmlFile(const QString &mainQml) Q_DECL_NOEXCEPT_EXPR(false)
{
- // For some weird reason, QFile cannot cope with "qrc:/" and QUrl cannot cope with ":/" , so
- // we have to translate ourselves between those two "worlds".
+ // For some weird reason, QFile cannot cope with "qrc:/" and QUrl cannot cope with ":/",
+ // so we have to translate ourselves between those two "worlds".
- if (mainQml.startsWith(qSL(":/")))
- m_mainQml = QUrl(qSL("qrc:") + mainQml.mid(1));
- else
- m_mainQml = QUrl::fromUserInput(mainQml, QDir::currentPath(), QUrl::AssumeLocalFile);
+ m_mainQml = filePathToUrl(mainQml, QDir::currentPath());
+ m_mainQmlLocalFile = urlToLocalFilePath(m_mainQml);
- if (m_mainQml.isLocalFile())
- m_mainQmlLocalFile = m_mainQml.toLocalFile();
- else if (m_mainQml.scheme() == qSL("qrc"))
- m_mainQmlLocalFile = qL1C(':') + m_mainQml.path();
+ if (!QFileInfo(m_mainQmlLocalFile).isFile()) {
+ if (mainQml.isEmpty())
+ throw Exception("No main QML file specified");
- if (!m_mainQmlLocalFile.isEmpty() && !QFile::exists(m_mainQmlLocalFile))
- throw Exception("no/invalid main QML file specified: %1").arg(m_mainQmlLocalFile);
+ // basically accept schemes other than file and qrc:
+ if (!m_mainQmlLocalFile.isEmpty())
+ throw Exception("Invalid main QML file specified: %1").arg(mainQml);
+ }
}
void Main::setupSingleOrMultiProcess(bool forceSingleProcess, bool forceMultiProcess) Q_DECL_NOEXCEPT_EXPR(false)
@@ -413,106 +429,63 @@ void Main::setupRuntimesAndContainers(const QVariantMap &runtimeConfigurations,
StartupTimer::instance()->checkpoint("after runtime registration");
}
-void Main::setupInstallationLocations(const QVariantList &installationLocations)
-{
- m_installationLocations = InstallationLocation::parseInstallationLocations(installationLocations,
- hardwareId());
- if (m_installationLocations.isEmpty())
- qCWarning(LogDeployment) << "No installation locations defined in config file";
-}
-
-void Main::loadApplicationDatabase(const QString &databasePath, bool recreateDatabase,
- const QString &singleApp) Q_DECL_NOEXCEPT_EXPR(false)
+void Main::loadPackageDatabase(bool recreateDatabase, const QString &singlePackage) Q_DECL_NOEXCEPT_EXPR(false)
{
- if (singleApp.isEmpty()) {
- if (!QFile::exists(databasePath)) // make sure to create a database on the first run
- recreateDatabase = true;
- if (QFileInfo(databasePath).size() == 0) // cope with Windows' 0-byte left-overs
- recreateDatabase = true;
-
- if (recreateDatabase) {
- const QString dbDir = QFileInfo(databasePath).absolutePath();
- if (Q_UNLIKELY(!QDir(dbDir).exists()) && Q_UNLIKELY(!QDir::root().mkpath(dbDir)))
- throw Exception("could not create application database directory %1").arg(dbDir);
- }
- m_applicationDatabase.reset(new ApplicationDatabase(databasePath));
+ if (!singlePackage.isEmpty()) {
+ m_packageDatabase = new PackageDatabase(singlePackage);
} else {
- m_applicationDatabase.reset(new ApplicationDatabase());
- recreateDatabase = true;
+ m_packageDatabase = new PackageDatabase(m_builtinAppsManifestDirs, m_installationDir);
+ if (!recreateDatabase)
+ m_packageDatabase->enableLoadFromCache();
+ m_packageDatabase->enableSaveToCache();
}
+ m_packageDatabase->parse();
- if (Q_UNLIKELY(!m_applicationDatabase->isValid() && !recreateDatabase)) {
- throw Exception("database file %1 is not a valid application database: %2")
- .arg(m_applicationDatabase->name(), m_applicationDatabase->errorString());
- }
+ const QVector<PackageInfo *> allPackages =
+ m_packageDatabase->builtInPackages()
+ + m_packageDatabase->installedPackages();
- if (!m_applicationDatabase->isValid() || recreateDatabase) {
- QVector<AbstractApplicationInfo *> apps;
+ for (auto package : allPackages) {
+ // check that the runtimes are supported in this instance of the AM
+ auto apps = package->applications();
- if (!singleApp.isEmpty()) {
- apps = scanForApplication(singleApp, m_builtinAppsManifestDirs);
- } else {
- apps = scanForApplications(m_builtinAppsManifestDirs,
- m_installedAppsManifestDir,
- m_installationLocations);
+ for (const auto app : apps) {
+ if (!RuntimeFactory::instance()->manager(app->runtimeName()))
+ qCWarning(LogSystem) << "Application" << app->id() << "uses an unknown runtime:" << app->runtimeName();
}
-
- if (LogSystem().isDebugEnabled()) {
- qCDebug(LogSystem) << "Registering applications:";
- for (auto *app : qAsConst(apps)) {
- if (app->isAlias())
- qCDebug(LogSystem).nospace().noquote() << " * " << app->id();
- else
- qCDebug(LogSystem).nospace().noquote() << " * " << app->id() << " [at: "
- << static_cast<const ApplicationInfo*>(app)->codeDir().path() << "]";
- }
- }
-
- m_applicationDatabase->write(apps);
- qDeleteAll(apps);
}
- StartupTimer::instance()->checkpoint("after application database loading");
+ StartupTimer::instance()->checkpoint("after package database loading");
}
-void Main::setupIntents(const QMap<QString, int> &timeouts) Q_DECL_NOEXCEPT_EXPR(false)
+void Main::setupIntents(int disambiguationTimeout, int startApplicationTimeout,
+ int replyFromApplicationTimeout, int replyFromSystemTimeout) Q_DECL_NOEXCEPT_EXPR(false)
{
- m_intentServer = IntentAMImplementation::createIntentServerAndClientInstance(timeouts);
-
- qCDebug(LogSystem) << "Registering intents:";
-
- const auto apps = m_applicationManager->applications();
- for (AbstractApplication *app : apps)
- IntentAMImplementation::addApplicationIntents(app, m_intentServer);
-
- StartupTimer::instance()->checkpoint("after Intents setup");
+ m_intentServer = IntentAMImplementation::createIntentServerAndClientInstance(m_packageManager,
+ disambiguationTimeout,
+ startApplicationTimeout,
+ replyFromApplicationTimeout,
+ replyFromSystemTimeout);
+ StartupTimer::instance()->checkpoint("after IntentServer instantiation");
}
void Main::setupSingletons(const QList<QPair<QString, QString>> &containerSelectionConfiguration,
- int quickLaunchRuntimesPerContainer, qreal quickLaunchIdleLoad,
- const QString &singleApp) Q_DECL_NOEXCEPT_EXPR(false)
+ int quickLaunchRuntimesPerContainer,
+ qreal quickLaunchIdleLoad) Q_DECL_NOEXCEPT_EXPR(false)
{
+ m_packageManager = PackageManager::createInstance(m_packageDatabase, m_documentDir);
m_applicationManager = ApplicationManager::createInstance(m_isSingleProcessMode);
- if (m_applicationDatabase) {
- setupApplicationManagerWithDatabase();
- } else {
- QVector<AbstractApplicationInfo *> appInfoVector;
-
- if (!singleApp.isEmpty()) {
- appInfoVector = scanForApplication(singleApp, m_builtinAppsManifestDirs);
- } else {
- appInfoVector = scanForApplications(m_builtinAppsManifestDirs,
- m_installedAppsManifestDir,
- m_installationLocations);
- }
-
- QVector<AbstractApplication *> apps = AbstractApplication::fromApplicationInfoVector(appInfoVector);
- m_applicationManager->setApplications(apps);
- }
-
- if (!singleApp.isEmpty())
- m_applicationManager->enableSingleAppMode();
+ connect(&m_packageManager->internalSignals, &PackageManagerInternalSignals::registerApplication,
+ m_applicationManager, [this](ApplicationInfo *applicationInfo, Package *package) {
+ m_applicationManager->addApplication(applicationInfo, package);
+ qCDebug(LogSystem).nospace().noquote() << " ++ application: " << applicationInfo->id() << " [package: " << package->id() << "]";
+ });
+ connect(&m_packageManager->internalSignals, &PackageManagerInternalSignals::unregisterApplication,
+ m_applicationManager, [this](ApplicationInfo *applicationInfo, Package *package) {
+ m_applicationManager->removeApplication(applicationInfo, package);
+ qCDebug(LogSystem).nospace().noquote() << " -- application: " << applicationInfo->id() << " [package: " << package->id() << "]";
+ });
if (m_noSecurity)
m_applicationManager->setSecurityChecksEnabled(false);
@@ -535,27 +508,11 @@ void Main::setupSingletons(const QList<QPair<QString, QString>> &containerSelect
StartupTimer::instance()->checkpoint("after quick-launcher setup");
}
-void Main::setupApplicationManagerWithDatabase()
-{
- m_applicationManager->setApplications(m_applicationDatabase->read());
-
- connect(&m_applicationManager->internalSignals, &ApplicationManagerInternalSignals::applicationsChanged,
- this, [this]() {
- try {
- if (m_applicationDatabase)
- m_applicationDatabase->write(m_applicationManager->applications());
- } catch (const Exception &e) {
- qCCritical(LogInstaller) << "Failed to write the application database to disk:" << e.errorString();
- m_applicationDatabase->invalidate(); // make sure that the next AM start will rebuild the DB
- }
- });
-}
-
void Main::setupInstaller(const QStringList &caCertificatePaths,
const std::function<bool(uint *, uint *, uint *)> &userIdSeparation) Q_DECL_NOEXCEPT_EXPR(false)
{
#if !defined(AM_DISABLE_INSTALLER)
- if (!Package::checkCorrectLocale()) {
+ if (!PackageUtilities::checkCorrectLocale()) {
// we should really throw here, but so many embedded systems are badly set up
qCWarning(LogDeployment) << "The appman installer needs a UTF-8 locale to work correctly: "
"even automatically switching to C.UTF-8 or en_US.UTF-8 failed.";
@@ -564,24 +521,20 @@ void Main::setupInstaller(const QStringList &caCertificatePaths,
if (Q_UNLIKELY(hardwareId().isEmpty()))
throw Exception("the installer is enabled, but the device-id is empty");
- if (Q_UNLIKELY(!QDir::root().mkpath(m_installedAppsManifestDir)))
- throw Exception("could not create manifest directory for installed applications: \'%1\'").arg(m_installedAppsManifestDir);
+ if (!m_installationDir.isEmpty() && !QDir::root().mkpath(m_installationDir))
+ throw Exception("could not create package installation directory: \'%1\'").arg(m_installationDir);
+ if (!m_documentDir.isEmpty() && !QDir::root().mkpath(m_documentDir))
+ throw Exception("could not create document directory for packages: \'%1\'").arg(m_documentDir);
StartupTimer::instance()->checkpoint("after installer setup checks");
- QString error;
- m_applicationInstaller = ApplicationInstaller::createInstance(m_installationLocations,
- m_installedAppsManifestDir,
- hardwareId(),
- &error);
- if (Q_UNLIKELY(!m_applicationInstaller))
- throw Exception(Error::System, error);
+ m_applicationInstaller = ApplicationInstaller::createInstance(m_packageManager);
if (m_developmentMode)
- m_applicationInstaller->setDevelopmentMode(true);
+ m_packageManager->setDevelopmentMode(true);
if (m_noSecurity) {
- m_applicationInstaller->setAllowInstallationOfUnsignedPackages(true);
+ m_packageManager->setAllowInstallationOfUnsignedPackages(true);
} else {
QList<QByteArray> caCertificateList;
@@ -594,13 +547,13 @@ void Main::setupInstaller(const QStringList &caCertificatePaths,
throw Exception(f, "CA-certificate file is empty");
caCertificateList << cert;
}
- m_applicationInstaller->setCACertificates(caCertificateList);
+ m_packageManager->setCACertificates(caCertificateList);
}
uint minUserId, maxUserId, commonGroupId;
if (userIdSeparation && userIdSeparation(&minUserId, &maxUserId, &commonGroupId)) {
# if defined(Q_OS_LINUX)
- if (!m_applicationInstaller->enableApplicationUserIdSeparation(minUserId, maxUserId, commonGroupId))
+ if (!m_packageManager->enableApplicationUserIdSeparation(minUserId, maxUserId, commonGroupId))
throw Exception("could not enable application user-id separation in the installer.");
# else
qCCritical(LogSystem) << "WARNING: application user-id separation requested, but not possible on this platform.";
@@ -608,12 +561,21 @@ void Main::setupInstaller(const QStringList &caCertificatePaths,
}
//TODO: this could be delayed, but needs to have a lock on the app-db in this case
- m_applicationInstaller->cleanupBrokenInstallations();
+ m_packageManager->cleanupBrokenInstallations();
- StartupTimer::instance()->checkpoint("after ApplicationInstaller instantiation");
+ StartupTimer::instance()->checkpoint("after installer setup");
+#else
+ Q_UNUSED(caCertificatePaths)
+ Q_UNUSED(userIdSeparation)
#endif // AM_DISABLE_INSTALLER
}
+void Main::registerPackages()
+{
+ m_packageManager->registerPackages();
+ StartupTimer::instance()->checkpoint("after package registration");
+}
+
void Main::setupQmlEngine(const QStringList &importPaths, const QString &quickControlsStyle)
{
if (!quickControlsStyle.isEmpty())
@@ -1003,9 +965,9 @@ void Main::setupDBus(const std::function<QString(const char *)> &busForInterface
};
# if !defined(AM_DISABLE_INSTALLER)
- if (m_applicationInstaller) {
- addInterface(new ApplicationInstallerDBusContextAdaptor(m_applicationInstaller),
- "io.qt.ApplicationManager", "/ApplicationInstaller");
+ if (m_packageManager) {
+ addInterface(new PackageManagerDBusContextAdaptor(m_packageManager),
+ "io.qt.ApplicationManager", "/PackageManager");
}
# endif
# if !defined(AM_HEADLESS)
@@ -1072,149 +1034,6 @@ void Main::setupDBus(const std::function<QString(const char *)> &busForInterface
#endif // defined(QT_DBUS_LIB) && !defined(AM_DISABLE_EXTERNAL_DBUS_INTERFACES)
}
-
-QVector<AbstractApplicationInfo *> Main::scanForApplication(const QString &singleAppInfoYaml,
- const QStringList &builtinAppsDirs) Q_DECL_NOEXCEPT_EXPR(false)
-{
- QVector<AbstractApplicationInfo *> result;
- YamlApplicationScanner yas;
-
- QDir appDir = QFileInfo(singleAppInfoYaml).dir();
-
- QScopedPointer<ApplicationInfo> a(yas.scan(singleAppInfoYaml));
- Q_ASSERT(a);
-
- if (!RuntimeFactory::instance()->manager(a->runtimeName())) {
- qCDebug(LogSystem) << "Ignoring application" << a->id() << ", because it uses an unknown runtime:" << a->runtimeName();
- return result;
- }
-
- QStringList aliasPaths = appDir.entryList(QStringList(qSL("info-*.yaml")));
- std::vector<std::unique_ptr<AbstractApplicationInfo>> aliases;
-
- for (int i = 0; i < aliasPaths.size(); ++i) {
- std::unique_ptr<AbstractApplicationInfo> alias(yas.scanAlias(appDir.absoluteFilePath(aliasPaths.at(i)), a.data()));
-
- Q_ASSERT(alias);
- Q_ASSERT(alias->isAlias());
-
- aliases.push_back(std::move(alias));
- }
-
- if (appDir.cdUp()) {
- for (const QString &dir : builtinAppsDirs) {
- if (appDir == QDir(dir)) {
- a->setBuiltIn(true);
- break;
- }
- }
- }
-
- result << a.take();
- for (auto &&alias : aliases)
- result << alias.release();
-
- return result;
-}
-
-QVector<AbstractApplicationInfo *> Main::scanForApplications(const QStringList &builtinAppsDirs, const QString &installedAppsDir,
- const QVector<InstallationLocation> &installationLocations) Q_DECL_NOEXCEPT_EXPR(false)
-{
- QVector<AbstractApplicationInfo *> result;
- YamlApplicationScanner yas;
-
- auto scan = [&result, &yas, &installationLocations](const QDir &baseDir, bool scanningBuiltinApps) {
- auto flags = scanningBuiltinApps ? QDir::Dirs | QDir::NoDotAndDotDot
- : QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks;
- const QStringList appDirNames = baseDir.entryList(flags);
-
- for (const QString &appDirName : appDirNames) {
- if (appDirName.endsWith('+') || appDirName.endsWith('-'))
- continue;
- QString appIdError;
- if (!AbstractApplicationInfo::isValidApplicationId(appDirName, false, &appIdError)) {
- qCDebug(LogSystem) << "Ignoring application directory" << appDirName
- << ": not a valid application-id:" << qPrintable(appIdError);
- continue;
- }
- QDir appDir = baseDir.absoluteFilePath(appDirName);
- if (!appDir.exists())
- continue;
- if (!appDir.exists(qSL("info.yaml"))) {
- qCDebug(LogSystem) << "Couldn't find a info.yaml in:" << appDir;
- continue;
- }
- if (!scanningBuiltinApps && !appDir.exists(qSL("installation-report.yaml")))
- continue;
-
- QScopedPointer<ApplicationInfo> a(yas.scan(appDir.absoluteFilePath(qSL("info.yaml"))));
- Q_ASSERT(a);
-
- AbstractRuntimeManager *runtimeManager = RuntimeFactory::instance()->manager(a->runtimeName());
- if (!runtimeManager) {
- qCDebug(LogSystem) << "Ignoring application" << a->id() << ", because it uses an unknown runtime:" << a->runtimeName();
- continue;
- }
- if (runtimeManager->supportsQuickLaunch()) {
- if (a->supportsApplicationInterface())
- qCDebug(LogSystem) << "Ignoring supportsApplicationInterface for application" << a->id() <<
- "as the runtime launcher supports it by default";
- a->setSupportsApplicationInterface(true);
- }
- if (a->id() != appDirName) {
- throw Exception(Error::Parse, "an info.yaml for built-in applications must be in a directory "
- "that has the same name as the application's id: found %1 in %2")
- .arg(a->id(), appDirName);
- }
- if (scanningBuiltinApps) {
- a->setBuiltIn(true);
- QStringList aliasPaths = appDir.entryList(QStringList(qSL("info-*.yaml")));
- std::vector<std::unique_ptr<AbstractApplicationInfo>> aliases;
-
- for (int i = 0; i < aliasPaths.size(); ++i) {
- std::unique_ptr<AbstractApplicationInfo> alias(yas.scanAlias(appDir.absoluteFilePath(aliasPaths.at(i)), a.data()));
-
- Q_ASSERT(alias);
- Q_ASSERT(alias->isAlias());
-
- aliases.push_back(std::move(alias));
- }
- result << a.take();
- for (auto &&alias : aliases)
- result << alias.release();
- } else { // 3rd-party apps
- QFile f(appDir.absoluteFilePath(qSL("installation-report.yaml")));
- if (!f.open(QFile::ReadOnly))
- continue;
-
- QScopedPointer<InstallationReport> report(new InstallationReport(a->id()));
- if (!report->deserialize(&f))
- continue;
-
-#if !defined(AM_DISABLE_INSTALLER)
- // fix the basedir of the application
- for (const InstallationLocation &il : installationLocations) {
- if (il.id() == report->installationLocationId()) {
- a->setCodeDir(il.installationPath() + a->id());
- break;
- }
- }
-#endif
- a->setInstallationReport(report.take());
- result << a.take();
- }
- }
- };
-
- for (const QString &dir : builtinAppsDirs)
- scan(dir, true);
-#if !defined(AM_DISABLE_INSTALLER)
- if (!installedAppsDir.isEmpty())
- scan(installedAppsDir, false);
-#endif
- return result;
-}
-
QString Main::hardwareId() const
{
static QString hardwareId;
diff --git a/src/main-lib/main.h b/src/main-lib/main.h
index 28838e6e..9e3b5992 100644
--- a/src/main-lib/main.h
+++ b/src/main-lib/main.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -59,7 +60,6 @@ typedef QApplication MainBase;
typedef QGuiApplication MainBase;
#endif
-#include <QtAppManInstaller/installationlocation.h>
#include <QtAppManSharedMain/sharedmain.h>
#include <QVector>
@@ -71,10 +71,11 @@ class StartupInterface;
QT_BEGIN_NAMESPACE_AM
-class AbstractApplicationInfo;
+class ApplicationInfo;
class StartupTimer;
class ApplicationIPCManager;
-class ApplicationDatabase;
+class PackageDatabase;
+class PackageManager;
class ApplicationManager;
class ApplicationInstaller;
class NotificationManager;
@@ -82,8 +83,7 @@ class IntentServer;
class WindowManager;
class QuickLauncher;
class SystemMonitor;
-class DefaultConfiguration;
-
+class Configuration;
class Main : public MainBase, protected SharedMain
{
@@ -96,7 +96,7 @@ public:
bool isSingleProcessMode() const;
- void setup(const DefaultConfiguration *cfg, const QStringList &deploymentWarnings = QStringList()) Q_DECL_NOEXCEPT_EXPR(false);
+ void setup(const Configuration *cfg, const QStringList &deploymentWarnings = QStringList()) Q_DECL_NOEXCEPT_EXPR(false);
void loadQml(bool loadDummyData) Q_DECL_NOEXCEPT_EXPR(false);
void showWindow(bool showFullscreen);
@@ -105,6 +105,7 @@ public:
QQmlApplicationEngine *qmlEngine() const;
protected:
+ void registerResources(const QStringList &resources) const;
void loadStartupPlugins(const QStringList &startupPluginPaths) Q_DECL_NOEXCEPT_EXPR(false);
void parseSystemProperties(const QVariantMap &rawSystemProperties);
void setupDBus(const std::function<QString(const char *)> &busForInterface,
@@ -114,15 +115,14 @@ protected:
void setupRuntimesAndContainers(const QVariantMap &runtimeConfigurations, const QVariantMap &openGLConfiguration,
const QVariantMap &containerConfigurations, const QStringList &containerPluginPaths,
const QStringList &iconThemeSearchPaths, const QString &iconThemeName);
- void setupInstallationLocations(const QVariantList &installationLocations);
- void loadApplicationDatabase(const QString &databasePath, bool recreateDatabase,
- const QString &singleApp) Q_DECL_NOEXCEPT_EXPR(false);
- void setupIntents(const QMap<QString, int> &timeouts) Q_DECL_NOEXCEPT_EXPR(false);
+ void loadPackageDatabase(bool recreateDatabase, const QString &singlePackage) Q_DECL_NOEXCEPT_EXPR(false);
+ void setupIntents(int disambiguationTimeout, int startApplicationTimeout,
+ int replyFromApplicationTimeout, int replyFromSystemTimeout) Q_DECL_NOEXCEPT_EXPR(false);
void setupSingletons(const QList<QPair<QString, QString>> &containerSelectionConfiguration,
- int quickLaunchRuntimesPerContainer, qreal quickLaunchIdleLoad,
- const QString &singleApp) Q_DECL_NOEXCEPT_EXPR(false);
+ int quickLaunchRuntimesPerContainer, qreal quickLaunchIdleLoad) Q_DECL_NOEXCEPT_EXPR(false);
void setupInstaller(const QStringList &caCertificatePaths,
const std::function<bool(uint *, uint *, uint *)> &userIdSeparation) Q_DECL_NOEXCEPT_EXPR(false);
+ void registerPackages();
void setupQmlEngine(const QStringList &importPaths, const QString &quickControlsStyle = QString());
void setupWindowTitle(const QString &title, const QString &iconPath);
@@ -145,16 +145,8 @@ private:
void registerDBusObject(QDBusAbstractAdaptor *adaptor, QString dbusName, const char *serviceName,
const char *interfaceName, const char *path) Q_DECL_NOEXCEPT_EXPR(false);
#endif
- static QVector<AbstractApplicationInfo *> scanForApplication(const QString &singleAppInfoYaml,
- const QStringList &builtinAppsDirs) Q_DECL_NOEXCEPT_EXPR(false);
- static QVector<AbstractApplicationInfo *> scanForApplications(const QStringList &builtinAppsDirs,
- const QString &installedAppsDir,
- const QVector<InstallationLocation> &installationLocations) Q_DECL_NOEXCEPT_EXPR(false);
-
- void setupApplicationManagerWithDatabase();
private:
- QVector<InstallationLocation> m_installationLocations;
bool m_isSingleProcessMode = false;
QUrl m_mainQml;
QString m_mainQmlLocalFile;
@@ -162,10 +154,13 @@ private:
QQmlApplicationEngine *m_engine = nullptr;
QQuickView *m_view = nullptr; // only set if we allocate the window ourselves
- QScopedPointer<ApplicationDatabase> m_applicationDatabase;
+ PackageDatabase *m_packageDatabase = nullptr;
+ PackageManager *m_packageManager = nullptr;
ApplicationManager *m_applicationManager = nullptr;
ApplicationIPCManager *m_applicationIPCManager = nullptr;
+#if !defined(AM_DISABLE_INSTALLER)
ApplicationInstaller *m_applicationInstaller = nullptr;
+#endif
NotificationManager *m_notificationManager = nullptr;
IntentServer *m_intentServer = nullptr;
WindowManager *m_windowManager = nullptr;
@@ -176,7 +171,8 @@ private:
bool m_noSecurity = false;
bool m_developmentMode = false;
QStringList m_builtinAppsManifestDirs;
- QString m_installedAppsManifestDir;
+ QString m_installationDir;
+ QString m_documentDir;
};
QT_END_NAMESPACE_AM
diff --git a/src/main-lib/windowframetimer.cpp b/src/main-lib/windowframetimer.cpp
index 11cc342e..c240023e 100644
--- a/src/main-lib/windowframetimer.cpp
+++ b/src/main-lib/windowframetimer.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/main-lib/windowframetimer.h b/src/main-lib/windowframetimer.h
index 098cacff..de9aefcf 100644
--- a/src/main-lib/windowframetimer.h
+++ b/src/main-lib/windowframetimer.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/abstractcontainer.cpp b/src/manager-lib/abstractcontainer.cpp
index 8827c788..aa444268 100644
--- a/src/manager-lib/abstractcontainer.cpp
+++ b/src/manager-lib/abstractcontainer.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -118,7 +118,7 @@ AbstractContainerProcess *AbstractContainer::process() const
return m_process;
}
-void AbstractContainer::setApplication(AbstractApplication *app)
+void AbstractContainer::setApplication(Application *app)
{
if (app != m_app) {
m_app = app;
@@ -126,12 +126,12 @@ void AbstractContainer::setApplication(AbstractApplication *app)
}
}
-AbstractApplication *AbstractContainer::application() const
+Application *AbstractContainer::application() const
{
return m_app;
}
-AbstractContainer::AbstractContainer(AbstractContainerManager *manager, AbstractApplication *app)
+AbstractContainer::AbstractContainer(AbstractContainerManager *manager, Application *app)
: QObject(manager)
, m_manager(manager)
, m_app(app)
diff --git a/src/manager-lib/abstractcontainer.h b/src/manager-lib/abstractcontainer.h
index 15e7d1f1..435c9eba 100644
--- a/src/manager-lib/abstractcontainer.h
+++ b/src/manager-lib/abstractcontainer.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -52,7 +52,7 @@
QT_BEGIN_NAMESPACE_AM
-class AbstractApplication;
+class Application;
class AbstractContainer;
class AbstractContainerManager : public QObject
@@ -66,7 +66,7 @@ public:
QString identifier() const;
virtual bool supportsQuickLaunch() const;
- virtual AbstractContainer *create(AbstractApplication *app, const QVector<int> &stdioRedirections,
+ virtual AbstractContainer *create(Application *app, const QVector<int> &stdioRedirections,
const QMap<QString, QString> &debugWrapperEnvironment,
const QStringList &debugWrapperCommand) = 0;
@@ -124,17 +124,17 @@ public:
AbstractContainerProcess *process() const;
- void setApplication(AbstractApplication *app);
- AbstractApplication *application() const;
+ void setApplication(Application *app);
+ Application *application() const;
signals:
void ready();
void memoryLowWarning();
void memoryCriticalWarning();
- void applicationChanged(AbstractApplication *newApplication);
+ void applicationChanged(Application *newApplication);
protected:
- explicit AbstractContainer(AbstractContainerManager *manager, AbstractApplication *app);
+ explicit AbstractContainer(AbstractContainerManager *manager, Application *app);
QVariantMap configuration() const;
@@ -142,7 +142,7 @@ protected:
QString m_baseDirectory;
AbstractContainerManager *m_manager;
AbstractContainerProcess *m_process = nullptr;
- AbstractApplication *m_app;
+ Application *m_app;
};
QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/abstractruntime.cpp b/src/manager-lib/abstractruntime.cpp
index 1c4ba03f..ec34aabd 100644
--- a/src/manager-lib/abstractruntime.cpp
+++ b/src/manager-lib/abstractruntime.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/abstractruntime.h b/src/manager-lib/abstractruntime.h
index 8276be47..ef70120b 100644
--- a/src/manager-lib/abstractruntime.h
+++ b/src/manager-lib/abstractruntime.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/amnamespace.h b/src/manager-lib/amnamespace.h
index f407da90..c144f96b 100644
--- a/src/manager-lib/amnamespace.h
+++ b/src/manager-lib/amnamespace.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/application.cpp b/src/manager-lib/application.cpp
index 9ba85ff6..f1a83d10 100644
--- a/src/manager-lib/application.cpp
+++ b/src/manager-lib/application.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -43,14 +44,12 @@
#include "application.h"
#include "abstractruntime.h"
#include "applicationinfo.h"
+#include "package.h"
#include "exception.h"
#include "logging.h"
#include <QDebug>
-#if defined(Q_OS_UNIX)
-# include <signal.h>
-#endif
/*!
\qmltype ApplicationObject
@@ -90,9 +89,12 @@
/*!
\qmlproperty string ApplicationObject::documentUrl
\readonly
+ \obsolete
- This property always returns the default \c documentUrl specified in the manifest file, even if
- a different URL was used to start the application.
+ This was used to distinguish between application aliases, which have been replaced by the
+ intents mechanism.
+
+ Always returns an empty string.
*/
/*!
\qmlproperty bool ApplicationObject::builtIn
@@ -104,22 +106,22 @@
/*!
\qmlproperty bool ApplicationObject::alias
\readonly
+ \obsolete
- Will return \c true if this ApplicationObject object is an alias to another one.
+ This was used to distinguish between application aliases, which have been replaced by the
+ intents mechanism.
- \sa nonAliased
+ Always returns \c false.
*/
/*!
\qmlproperty ApplicationObject ApplicationObject::nonAliased
\readonly
+ \obsolete
- If this ApplicationObject is an alias, then you can access the non-alias, base ApplicationObject
- via this property, otherwise it contains a reference to itself. This means that if you're interested
- in accessing the base application regardless of whether the object at hand is just an alias, you
- can always safely refer to this property.
+ This was used to distinguish between application aliases, which have been replaced by the
+ intents mechanism.
- If you want to know whether this object is an alias or a base ApplicationObject, use
- ApplicationObject::alias instead.
+ Always returns the object itself.
*/
/*!
\qmlproperty list<string> ApplicationObject::capabilities
@@ -190,10 +192,7 @@
\qmlproperty string ApplicationObject::codeDir
\readonly
- The absolute path to the application's installation directory. Please note this directory might
- not always be available for applications that were installed onto removable media.
-
- \sa {Installation Locations}
+ The absolute path to the application's installation directory.
*/
/*!
\qmlproperty enumeration ApplicationObject::state
@@ -272,232 +271,168 @@
QT_BEGIN_NAMESPACE_AM
+
///////////////////////////////////////////////////////////////////////////////////////////////////
-// AbstractApplication
+// Application
///////////////////////////////////////////////////////////////////////////////////////////////////
-AbstractApplication::AbstractApplication(AbstractApplicationInfo *info)
+Application::Application(ApplicationInfo *info, Package *package)
: m_info(info)
+ , m_package(package)
{
+ Q_ASSERT(info);
+ Q_ASSERT(package);
+
+ // handle package blocking: all apps have to be stopped and the stop state has to be reported
+ // back to the package
+
+ connect(package, &Package::blockedChanged, this, [this](bool blocked) {
+ emit blockedChanged(blocked);
+ if (blocked && (runState() == Am::NotRunning))
+ this->package()->applicationStoppedDueToBlock(id());
+ else if (blocked)
+ stop(true);
+ });
+ connect(this, &Application::runStateChanged, this, [this](Am::RunState runState) {
+ if (isBlocked() && (runState == Am::NotRunning))
+ this->package()->applicationStoppedDueToBlock(id());
+ });
+
+ connect(package, &Package::stateChanged, this, [this]() {
+ emit stateChanged(state());
+ });
+ connect(package, &Package::bulkChange, this, &Application::bulkChange);
}
-QString AbstractApplication::id() const
+bool Application::start(const QString &documentUrl)
{
- return m_info->id();
+ if (requests.startRequested)
+ return requests.startRequested(documentUrl);
+ else
+ return false;
}
-QUrl AbstractApplication::icon() const
+bool Application::debug(const QString &debugWrapper, const QString &documentUrl)
{
- if (info()->icon().isEmpty())
- return QUrl();
-
- auto appInfo = this->nonAliasedInfo();
- QDir dir;
- switch (state()) {
- default:
- case Installed:
- dir.setPath(appInfo->manifestDir());
- break;
- case BeingInstalled:
- case BeingUpdated:
- dir.setPath(appInfo->codeDir().absolutePath() + QLatin1Char('+'));
- break;
- case BeingRemoved:
- dir.setPath(appInfo->codeDir().absolutePath() + QLatin1Char('-'));
- break;
- }
- return QUrl::fromLocalFile(dir.absoluteFilePath(info()->icon()));
+ if (requests.debugRequested)
+ return requests.debugRequested(debugWrapper, documentUrl);
+ else
+ return false;
}
-QString AbstractApplication::documentUrl() const
+void Application::stop(bool forceKill)
{
- return info()->documentUrl();
+ if (requests.stopRequested)
+ requests.stopRequested(forceKill);
}
-bool AbstractApplication::isBuiltIn() const
+ApplicationInfo *Application::info() const
{
- return nonAliasedInfo()->isBuiltIn();
+ return m_info;
}
-bool AbstractApplication::isAlias() const
+PackageInfo *Application::packageInfo() const
{
- return info()->isAlias();
+ return m_info->packageInfo();
}
-QStringList AbstractApplication::capabilities() const
+Package *Application::package() const
{
- return nonAliasedInfo()->capabilities();
+ return m_package;
}
-QStringList AbstractApplication::supportedMimeTypes() const
+QString Application::id() const
{
- return nonAliasedInfo()->supportedMimeTypes();
+ return m_info->id();
}
-QStringList AbstractApplication::categories() const
+bool Application::isBuiltIn() const
{
- return nonAliasedInfo()->categories();
+ return packageInfo()->isBuiltIn();
}
-QVariantMap AbstractApplication::applicationProperties() const
+QString Application::runtimeName() const
{
- return info()->applicationProperties();
+ return m_info->runtimeName();
}
-bool AbstractApplication::supportsApplicationInterface() const
+QVariantMap Application::runtimeParameters() const
{
- return nonAliasedInfo()->supportsApplicationInterface();
+ return m_info->runtimeParameters();
}
-QString AbstractApplication::version() const
+QStringList Application::capabilities() const
{
- return nonAliasedInfo()->version();
+ return m_info->capabilities();
}
-QString AbstractApplication::codeDir() const
+QStringList Application::categories() const
{
- switch (state()) {
- default:
- case Installed:
- return nonAliasedInfo()->codeDir().absolutePath();
- case BeingInstalled:
- case BeingUpdated:
- return nonAliasedInfo()->codeDir().absolutePath() + QLatin1Char('+');
- case BeingRemoved:
- return nonAliasedInfo()->codeDir().absolutePath() + QLatin1Char('-');
- }
+ return package()->categories();
}
-QString AbstractApplication::name(const QString &language) const
+QUrl Application::icon() const
{
- return info()->name(language);
+ return package()->icon();
}
-bool AbstractApplication::start(const QString &documentUrl)
+QStringList Application::supportedMimeTypes() const
{
- if (requests.startRequested)
- return requests.startRequested(documentUrl);
- else
- return false;
+ return info()->supportedMimeTypes();
}
-bool AbstractApplication::debug(const QString &debugWrapper, const QString &documentUrl)
+QString Application::name() const
{
- if (requests.debugRequested)
- return requests.debugRequested(debugWrapper, documentUrl);
- else
- return false;
+ return package()->name();
}
-void AbstractApplication::stop(bool forceKill)
+QString Application::name(const QString &language) const
{
- if (requests.stopRequested)
- requests.stopRequested(forceKill);
+ return package()->names().value(language).toString();
}
-QVector<AbstractApplication *> AbstractApplication::fromApplicationInfoVector(
- QVector<AbstractApplicationInfo *> &appInfoVector)
+bool Application::isBlocked() const
{
- QVector<AbstractApplication *> apps;
-
- auto findAppWithId = [&apps] (const QString &id) -> AbstractApplication*
- {
- for (AbstractApplication *app : apps) {
- if (app->id() == id)
- return app;
- }
- return nullptr;
- };
-
- auto extractBaseId = [] (const QString &id) -> QString
- {
- return id.section(qL1C('@'), 0, 0);
- };
-
- for (auto *appInfo : appInfoVector) {
- QScopedPointer<AbstractApplication> app;
- if (appInfo->isAlias()) {
- auto *originalApp = findAppWithId(extractBaseId(appInfo->id()));
- if (!originalApp)
- throw Exception(Error::Parse, "Could not find base app for alias id %2").arg(appInfo->id());
- Q_ASSERT(!originalApp->isAlias());
- app.reset(new ApplicationAlias(static_cast<Application*>(originalApp),
- static_cast<ApplicationAliasInfo*>(appInfo)));
- } else {
- AbstractApplication *otherAbsApp = findAppWithId(appInfo->id());
- if (otherAbsApp) {
- // There's already another ApplicationInfo with the same id. It's probably an update for a
- // built-in app, in which case we use the same Application instance to hold both
- // ApplicationInfo instances.
- if (!otherAbsApp->isAlias()) {
- auto otherApp = static_cast<Application*>(otherAbsApp);
- auto fullAppInfo = static_cast<ApplicationInfo*>(appInfo);
- if (otherApp->isBuiltIn() && !fullAppInfo->isBuiltIn() && !otherApp->updatedInfo()) {
- otherApp->setUpdatedInfo(static_cast<ApplicationInfo*>(appInfo));
- } else if (!otherApp->isBuiltIn() && fullAppInfo->isBuiltIn() && !otherApp->updatedInfo()) {
- auto currentBaseInfo = otherApp->takeBaseInfo();
- otherApp->setBaseInfo(static_cast<ApplicationInfo*>(appInfo));
- otherApp->setUpdatedInfo(currentBaseInfo);
- }
- } else {
- qCWarning(LogSystem) << "Found a second application with id" << appInfo->id()
- << "which is not an update for a built-in one. Ignoring it.";
- }
- } else {
- app.reset(new Application(static_cast<ApplicationInfo*>(appInfo)));
- }
- }
-
- if (!app.isNull())
- apps << app.take();
- }
-
- return apps;
+ return package()->isBlocked();
}
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Application
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-Application::Application(ApplicationInfo *info, State initialState)
- : AbstractApplication(info)
- , m_state(initialState)
+QVariantMap Application::applicationProperties() const
{
+ return info()->applicationProperties();
}
-void Application::setCurrentRuntime(AbstractRuntime *rt)
+bool Application::supportsApplicationInterface() const
{
- if (m_runtime == rt)
- return;
-
- if (m_runtime)
- disconnect(m_runtime, nullptr, this, nullptr);
-
- m_runtime = rt;
- emit runtimeChanged();
+ return info()->supportsApplicationInterface();
+}
- if (m_runtime) {
- connect(m_runtime, &AbstractRuntime::finished, this, &Application::setLastExitCodeAndStatus);
- connect(m_runtime, &QObject::destroyed, this, [this]() {
- this->setCurrentRuntime(nullptr);
- });
- } else
- setRunState(Am::NotRunning);
+QString Application::codeDir() const
+{
+ switch (package()->state()) {
+ default:
+ case Package::Installed:
+ return packageInfo()->baseDir().absolutePath();
+ case Package::BeingInstalled:
+ case Package::BeingUpdated:
+ return packageInfo()->baseDir().absolutePath() + QLatin1Char('+');
+ case Package::BeingRemoved:
+ return packageInfo()->baseDir().absolutePath() + QLatin1Char('-');
+ }
}
-bool Application::isBlocked() const
+QString Application::version() const
{
- return m_blocked.load() == 1;
+ return packageInfo()->version();
}
-bool Application::block()
+Application::State Application::state() const
{
- return m_blocked.testAndSetOrdered(0, 1);
+ return static_cast<State>(package()->state());
}
-bool Application::unblock()
+qreal Application::progress() const
{
- return m_blocked.testAndSetOrdered(1, 0);
+ return package()->progress();
}
void Application::setRunState(Am::RunState runState)
@@ -508,24 +443,25 @@ void Application::setRunState(Am::RunState runState)
}
}
-QString Application::runtimeName() const
+void Application::setCurrentRuntime(AbstractRuntime *runtime)
{
- return Application::nonAliasedInfo()->runtimeName();
-}
+ if (m_runtime == runtime)
+ return;
-QVariantMap Application::runtimeParameters() const
-{
- return Application::nonAliasedInfo()->runtimeParameters();
-}
+ if (m_runtime)
+ disconnect(m_runtime, nullptr, this, nullptr);
-AbstractApplicationInfo *Application::info() const
-{
- return m_updatedInfo ? m_updatedInfo.data() : m_info.data();
-}
+ m_runtime = runtime;
+ emit runtimeChanged();
-ApplicationInfo *Application::nonAliasedInfo() const
-{
- return static_cast<ApplicationInfo*>(Application::info());
+ if (m_runtime) {
+ connect(m_runtime, &AbstractRuntime::finished, this, &Application::setLastExitCodeAndStatus);
+ connect(m_runtime, &QObject::destroyed, this, [this]() {
+ this->setCurrentRuntime(nullptr);
+ });
+ } else {
+ setRunState(Am::NotRunning);
+ }
}
void Application::setLastExitCodeAndStatus(int exitCode, Am::ExitStatus exitStatus)
@@ -535,93 +471,15 @@ void Application::setLastExitCodeAndStatus(int exitCode, Am::ExitStatus exitStat
emit lastExitCodeChanged();
}
- Am::ExitStatus newStatus;
- if (exitStatus == Am::CrashExit) {
-#if defined(Q_OS_UNIX)
- newStatus = (exitCode == SIGTERM || exitCode == SIGKILL) ? Am::ForcedExit : Am::CrashExit;
-#else
- newStatus = Am::CrashExit;
-#endif
- } else {
- newStatus = Am::NormalExit;
- }
-
- if (m_lastExitStatus != newStatus) {
- m_lastExitStatus = newStatus;
+ if (m_lastExitStatus != exitStatus) {
+ m_lastExitStatus = exitStatus;
emit lastExitStatusChanged();
}
}
-void Application::setBaseInfo(ApplicationInfo *info)
-{
- m_info.reset(info);
- emit bulkChange();
-}
-
-ApplicationInfo *Application::takeBaseInfo()
-{
- return static_cast<ApplicationInfo*>(m_info.take());
-}
-
-void Application::setUpdatedInfo(ApplicationInfo* info)
-{
- Q_ASSERT(!info || (m_info && info->id() == m_info->id()));
-
- m_updatedInfo.reset(info);
- emit bulkChange();
-}
-
-ApplicationInfo *Application::takeUpdatedInfo()
-{
- return m_updatedInfo.take();
-}
-
-void Application::setState(State state)
-{
- if (m_state != state) {
- m_state = state;
- emit stateChanged(m_state);
- }
-}
-
-void Application::setProgress(qreal value)
-{
- m_progress = value;
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// ApplicationAlias
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-ApplicationAlias::ApplicationAlias(Application* app, ApplicationAliasInfo* info)
- : AbstractApplication(info)
- , m_application(app)
-{
- connect(m_application, &AbstractApplication::runtimeChanged, this, &AbstractApplication::runtimeChanged);
- connect(m_application, &AbstractApplication::lastExitCodeChanged, this, &AbstractApplication::lastExitCodeChanged);
- connect(m_application, &AbstractApplication::lastExitStatusChanged, this, &AbstractApplication::lastExitStatusChanged);
- connect(m_application, &AbstractApplication::stateChanged, this, &AbstractApplication::stateChanged);
- connect(m_application, &AbstractApplication::runStateChanged, this, &AbstractApplication::runStateChanged);
-}
-
-QString ApplicationAlias::runtimeName() const
-{
- return m_application->runtimeName();
-}
-
-QVariantMap ApplicationAlias::runtimeParameters() const
-{
- return m_application->runtimeParameters();
-}
-
-ApplicationInfo *ApplicationAlias::nonAliasedInfo() const
-{
- return m_application->nonAliasedInfo();
-}
-
QT_END_NAMESPACE_AM
-QDebug operator<<(QDebug debug, const QT_PREPEND_NAMESPACE_AM(AbstractApplication) *app)
+QDebug operator<<(QDebug debug, const QT_PREPEND_NAMESPACE_AM(Application) *app)
{
debug << "Application Object:";
if (app)
diff --git a/src/manager-lib/application.h b/src/manager-lib/application.h
index 4b7497e6..46616b1e 100644
--- a/src/manager-lib/application.h
+++ b/src/manager-lib/application.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -44,15 +45,16 @@
#include <QObject>
#include <QScopedPointer>
+#include <QVariantMap>
#include <QUrl>
#include <QtAppManApplication/applicationinfo.h>
+#include <QtAppManApplication/packageinfo.h>
#include <QtAppManManager/amnamespace.h>
#include <QtAppManCommon/global.h>
QT_BEGIN_NAMESPACE_AM
class AbstractRuntime;
-class Application;
// A place to collect functions used internally by appman without polluting
// Application's public QML API.
@@ -64,34 +66,39 @@ public:
std::function<void(bool forceKill)> stopRequested;
};
-class AbstractApplication : public QObject
+class Package;
+
+class Application : public QObject
{
Q_OBJECT
Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/ApplicationObject 2.0 UNCREATABLE")
Q_PROPERTY(QString id READ id CONSTANT)
- Q_PROPERTY(QString runtimeName READ runtimeName NOTIFY bulkChange)
- Q_PROPERTY(QVariantMap runtimeParameters READ runtimeParameters NOTIFY bulkChange)
+ Q_PROPERTY(QString runtimeName READ runtimeName CONSTANT)
+ Q_PROPERTY(QVariantMap runtimeParameters READ runtimeParameters CONSTANT)
Q_PROPERTY(QUrl icon READ icon NOTIFY bulkChange)
- Q_PROPERTY(QString documentUrl READ documentUrl NOTIFY bulkChange)
+ Q_PROPERTY(QString documentUrl READ documentUrl CONSTANT) // REMOVE
Q_PROPERTY(bool builtIn READ isBuiltIn CONSTANT)
- Q_PROPERTY(bool alias READ isAlias CONSTANT)
- Q_PROPERTY(Application* nonAliased READ nonAliased CONSTANT)
- Q_PROPERTY(QStringList capabilities READ capabilities NOTIFY bulkChange)
- Q_PROPERTY(QStringList supportedMimeTypes READ supportedMimeTypes NOTIFY bulkChange)
- Q_PROPERTY(QStringList categories READ categories NOTIFY bulkChange)
- Q_PROPERTY(QVariantMap applicationProperties READ applicationProperties NOTIFY bulkChange)
+ Q_PROPERTY(bool alias READ isAlias CONSTANT) // REMOVE
+ Q_PROPERTY(Application *nonAliased READ nonAliased CONSTANT) // REMOVE
+ Q_PROPERTY(QStringList capabilities READ capabilities CONSTANT)
+ Q_PROPERTY(QStringList supportedMimeTypes READ supportedMimeTypes CONSTANT) // REMOVE
+ Q_PROPERTY(QStringList categories READ categories CONSTANT)
+ Q_PROPERTY(QVariantMap applicationProperties READ applicationProperties CONSTANT)
Q_PROPERTY(AbstractRuntime *runtime READ currentRuntime NOTIFY runtimeChanged)
Q_PROPERTY(int lastExitCode READ lastExitCode NOTIFY lastExitCodeChanged)
Q_PROPERTY(QT_PREPEND_NAMESPACE_AM(Am::ExitStatus) lastExitStatus READ lastExitStatus NOTIFY lastExitStatusChanged)
- Q_PROPERTY(QString version READ version NOTIFY bulkChange)
- Q_PROPERTY(bool supportsApplicationInterface READ supportsApplicationInterface NOTIFY bulkChange)
+ Q_PROPERTY(QString version READ version CONSTANT)
+ Q_PROPERTY(bool supportsApplicationInterface READ supportsApplicationInterface CONSTANT)
Q_PROPERTY(QString codeDir READ codeDir NOTIFY bulkChange)
- Q_PROPERTY(State state READ state NOTIFY stateChanged)
Q_PROPERTY(QT_PREPEND_NAMESPACE_AM(Am::RunState) runState READ runState NOTIFY runStateChanged)
+ // legacy, forwarded to Package
+ Q_PROPERTY(State state READ state NOTIFY stateChanged)
+ Q_PROPERTY(bool blocked READ isBlocked NOTIFY blockedChanged)
+
public:
- enum State {
+ enum State { // kept for compatibility ... in reality moved to class Package
Installed,
BeingInstalled,
BeingUpdated,
@@ -100,62 +107,51 @@ public:
};
Q_ENUM(State)
- AbstractApplication(AbstractApplicationInfo *info);
+ Application(ApplicationInfo *info, Package *package);
Q_INVOKABLE bool start(const QString &documentUrl = QString());
Q_INVOKABLE bool debug(const QString &debugWrapper, const QString &documentUrl = QString());
Q_INVOKABLE void stop(bool forceKill = false);
- virtual Application *nonAliased() = 0;
-
- /*
- Returns information about this application, which can either
- be a full-fledged one (ApplicationInfo) or just an alias
- (ApplicationAliasInfo).
+ ApplicationInfo *info() const;
+ PackageInfo *packageInfo() const;
+ Package *package() const;
- Use info()->isAlias() to check and cast as appropriate.
- */
- virtual AbstractApplicationInfo *info() const = 0;
-
- /*
- Always returns information about the "concrete", non-aliased, application.
- This is the same as static_cast<ApplicationInfo*>(nonAliased()->info())
- */
- virtual ApplicationInfo *nonAliasedInfo() const = 0;
+ // legacy compatibility
+ bool isAlias() const { return false; }
+ Application *nonAliased() { return this; }
+ QStringList categories() const;
+ QUrl icon() const;
+ QString documentUrl() const { return QString {}; }
+ QStringList supportedMimeTypes() const;
+ QString name() const;
+ Q_INVOKABLE QString name(const QString &language) const;
+ bool isBlocked() const;
// Properties that mainly forward content from ApplicationInfo
QString id() const;
- virtual QString runtimeName() const = 0;
- virtual QVariantMap runtimeParameters() const = 0;
- QUrl icon() const;
- QString documentUrl() const;
bool isBuiltIn() const;
- bool isAlias() const;
+ QString runtimeName() const;
+ QVariantMap runtimeParameters() const;
QStringList capabilities() const;
- QStringList supportedMimeTypes() const;
- QStringList categories() const;
QVariantMap applicationProperties() const;
bool supportsApplicationInterface() const;
+ QString codeDir() const;
QString version() const;
- Q_INVOKABLE QString name(const QString &language) const;
// Properties present only in Application (not coming from ApplicationInfo)
- virtual AbstractRuntime *currentRuntime() const = 0;
- virtual State state() const = 0;
- QString codeDir() const;
- virtual bool isBlocked() const = 0;
- virtual bool block() = 0;
- virtual bool unblock() = 0;
- virtual qreal progress() const = 0;
- virtual Am::RunState runState() const = 0;
- virtual int lastExitCode() const = 0;
- virtual Am::ExitStatus lastExitStatus() const = 0;
+
+ AbstractRuntime *currentRuntime() const { return m_runtime; }
+ State state() const;
+ qreal progress() const;
+ Am::RunState runState() const { return m_runState; }
+ int lastExitCode() const { return m_lastExitCode; }
+ Am::ExitStatus lastExitStatus() const { return m_lastExitStatus; }
ApplicationRequests requests;
- // Creates a list of Applications from a list of ApplicationInfo objects.
- // Ownership of the given ApplicationInfo objects is passed to the returned Applications.
- static QVector<AbstractApplication *> fromApplicationInfoVector(QVector<AbstractApplicationInfo *> &);
+ void setRunState(Am::RunState runState);
+ void setCurrentRuntime(AbstractRuntime *runtime);
signals:
void bulkChange();
@@ -165,110 +161,24 @@ signals:
void activated();
void stateChanged(State state);
void runStateChanged(QT_PREPEND_NAMESPACE_AM(Am::RunState) state);
-
-protected:
- QScopedPointer<AbstractApplicationInfo> m_info;
-};
-
-class Application : public AbstractApplication
-{
- Q_OBJECT
-public:
- Application(ApplicationInfo *info, State initialState = Installed);
-
-
- // Returns the updated info, if there's one. Otherwise
- // returns the base info.
- AbstractApplicationInfo *info() const override;
-
- // same as info()
- ApplicationInfo *nonAliasedInfo() const override;
-
-
- /*
- All applications have a base info.
-
- Built-in applications, when updated, also get an updated info.
- The updated info then overlays the base one. Subsequent updates
- just replace the updated info. When requested to be removed, a
- built-in application only loses its updated info, returning to
- expose the base one.
-
- Regular applications (ie, non-built-in) only have a base info. When
- updated their base info gets replaced and thus there's no way to go
- back to a previous version. Regular applications get completely
- removed when requested.
- */
- void setBaseInfo(ApplicationInfo*);
- AbstractApplicationInfo *baseInfo() const { return m_info.data(); }
- ApplicationInfo *takeBaseInfo();
- void setUpdatedInfo(ApplicationInfo*);
- ApplicationInfo *updatedInfo() const { return m_updatedInfo.data(); }
- ApplicationInfo *takeUpdatedInfo();
-
- void setState(State);
- void setProgress(qreal);
- void setRunState(Am::RunState);
- void setCurrentRuntime(AbstractRuntime *rt);
-
- Application *nonAliased() override { return this; }
- QString runtimeName() const override;
- QVariantMap runtimeParameters() const override;
- AbstractRuntime *currentRuntime() const override { return m_runtime; }
- State state() const override { return m_state; }
- bool isBlocked() const override;
- bool block() override;
- bool unblock() override;
- qreal progress() const override { return m_progress; }
- Am::RunState runState() const override { return m_runState; }
- int lastExitCode() const override { return m_lastExitCode; }
- Am::ExitStatus lastExitStatus() const override { return m_lastExitStatus; }
+ void blockedChanged(bool blocked);
private:
void setLastExitCodeAndStatus(int exitCode, Am::ExitStatus exitStatus);
+ ApplicationInfo *m_info = nullptr;
+ Package *m_package = nullptr;
AbstractRuntime *m_runtime = nullptr;
- QAtomicInt m_blocked;
- QAtomicInt m_mounted;
- State m_state = Installed;
Am::RunState m_runState = Am::NotRunning;
- qreal m_progress = 0;
int m_lastExitCode = 0;
Am::ExitStatus m_lastExitStatus = Am::NormalExit;
- QScopedPointer<ApplicationInfo> m_updatedInfo;
-};
-
-class ApplicationAlias : public AbstractApplication
-{
- Q_OBJECT
-public:
- ApplicationAlias(Application*, ApplicationAliasInfo*);
-
- AbstractApplicationInfo *info() const override { return m_info.data(); }
- Application *nonAliased() override { return m_application; }
- QString runtimeName() const override;
- QVariantMap runtimeParameters() const override;
- AbstractRuntime *currentRuntime() const override { return m_application->currentRuntime(); }
- State state() const override { return m_application->state(); }
- bool isBlocked() const override { return m_application->isBlocked(); }
- bool block() override { return m_application->block(); }
- bool unblock() override { return m_application->unblock(); }
- qreal progress() const override { return m_application->progress(); }
- Am::RunState runState() const override { return m_application->runState(); }
- int lastExitCode() const override { return m_application->lastExitCode(); }
- Am::ExitStatus lastExitStatus() const override { return m_application->lastExitStatus(); }
-protected:
- // Returns info() from the application being aliased
- ApplicationInfo *nonAliasedInfo() const override;
-private:
- Application *m_application;
};
QT_END_NAMESPACE_AM
-Q_DECLARE_METATYPE(const QT_PREPEND_NAMESPACE_AM(AbstractApplication *))
+Q_DECLARE_METATYPE(const QT_PREPEND_NAMESPACE_AM(Application *))
-QDebug operator<<(QDebug debug, const QT_PREPEND_NAMESPACE_AM(AbstractApplication) *app);
+QDebug operator<<(QDebug debug, const QT_PREPEND_NAMESPACE_AM(Application) *app);
diff --git a/src/manager-lib/applicationdatabase.cpp b/src/manager-lib/applicationdatabase.cpp
deleted file mode 100644
index a6fb8ef3..00000000
--- a/src/manager-lib/applicationdatabase.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Luxoft Sweden AB
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Luxoft Application Manager.
-**
-** $QT_BEGIN_LICENSE:LGPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** 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-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: LGPL-3.0
-**
-****************************************************************************/
-
-#include <QFile>
-#include <QDataStream>
-#include <QTemporaryFile>
-#include <QScopedPointer>
-
-#include "application.h"
-#include "applicationdatabase.h"
-#include "exception.h"
-#include "logging.h"
-
-QT_BEGIN_NAMESPACE_AM
-
-class ApplicationDatabasePrivate
-{
-public:
- void validateWritableFile()
- {
- if (!file || !file->isOpen() || !file->isWritable())
- throw Exception("application database %1 is not opened for writing").arg(file ? file->fileName() : qSL("<null>"));
- if (!file->seek(0))
- throw Exception(*file, "could not not seek to position 0 in the application database");
- if (!file->resize(0))
- throw Exception(*file, "could not truncate the application database");
- }
-
- QFile *file = nullptr;
-
- ApplicationDatabasePrivate()
- { }
- ~ApplicationDatabasePrivate()
- { delete file; }
-};
-
-ApplicationDatabase::ApplicationDatabase(const QString &fileName)
- : d(new ApplicationDatabasePrivate())
-{
- d->file = new QFile(fileName);
- d->file->open(QFile::ReadWrite);
-}
-
-ApplicationDatabase::ApplicationDatabase()
- : d(new ApplicationDatabasePrivate())
-{
- d->file = new QTemporaryFile(qSL("am-apps-db"));
- d->file->open(QFile::ReadWrite);
-}
-
-ApplicationDatabase::~ApplicationDatabase()
-{
- delete d;
-}
-
-bool ApplicationDatabase::isValid() const
-{
- return d->file && d->file->isOpen();
-}
-
-bool ApplicationDatabase::isTemporary() const
-{
- return qobject_cast<QTemporaryFile *>(d->file);
-}
-
-QString ApplicationDatabase::errorString() const
-{
- return d->file->errorString();
-}
-
-QString ApplicationDatabase::name() const
-{
- return d->file->fileName();
-}
-
-QVector<AbstractApplication *> ApplicationDatabase::read() Q_DECL_NOEXCEPT_EXPR(false)
-{
- if (!d->file || !d->file->isOpen() || !d->file->isReadable())
- throw Exception("application database %1 is not opened for reading").arg(d->file ? d->file->fileName() : qSL("<null>"));
-
- QVector<AbstractApplicationInfo *> appInfoVector;
-
- if (d->file->seek(0)) {
- QDataStream ds(d->file);
- forever {
- QScopedPointer<AbstractApplicationInfo> appInfo(AbstractApplicationInfo::readFromDataStream(ds));
-
- if (ds.status() != QDataStream::Ok) {
- if (ds.status() != QDataStream::ReadPastEnd) {
- qDeleteAll(appInfoVector);
- throw Exception("could not read from application database %1").arg(d->file->fileName());
- }
- break;
- }
-
- appInfoVector.append(appInfo.take());
- }
- }
-
- return AbstractApplication::fromApplicationInfoVector(appInfoVector);
-}
-
-void ApplicationDatabase::write(const QVector<AbstractApplicationInfo *> &apps) Q_DECL_NOEXCEPT_EXPR(false)
-{
- d->validateWritableFile();
-
- QDataStream ds(d->file);
- for (auto *app : apps)
- app->writeToDataStream(ds);
-
- if (ds.status() != QDataStream::Ok)
- throw Exception(*d->file, "could not write to application database");
-}
-
-void ApplicationDatabase::write(const QVector<AbstractApplication *> &apps) Q_DECL_NOEXCEPT_EXPR(false)
-{
- d->validateWritableFile();
-
- QDataStream ds(d->file);
- for (auto *app : apps) {
- app->info()->writeToDataStream(ds);
- if (!app->isAlias()) {
- auto fullApp = static_cast<Application*>(app);
- if (fullApp->updatedInfo())
- fullApp->updatedInfo()->writeToDataStream(ds);
- }
- }
-
- if (ds.status() != QDataStream::Ok)
- throw Exception(*d->file, "could not write to application database");
-
- d->file->flush();
-}
-
-void ApplicationDatabase::invalidate()
-{
- if (d->file) {
- if (d->file->isOpen())
- d->file->close();
- d->file->remove();
- d->file = nullptr;
- }
-}
-
-QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/applicationipcinterface.cpp b/src/manager-lib/applicationipcinterface.cpp
index 9b9ec477..aa08991d 100644
--- a/src/manager-lib/applicationipcinterface.cpp
+++ b/src/manager-lib/applicationipcinterface.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -100,7 +100,7 @@ QString ApplicationIPCInterface::pathName() const
return m_ipcProxy ? m_ipcProxy->pathName() : QString();
}
-bool ApplicationIPCInterface::isValidForApplication(AbstractApplication *app) const
+bool ApplicationIPCInterface::isValidForApplication(Application *app) const
{
return m_ipcProxy ? m_ipcProxy->isValidForApplication(app) : false;
}
@@ -126,7 +126,7 @@ void ApplicationIPCInterface::setServiceObject(QObject *serviceObject)
}
#if defined(QT_DBUS_LIB)
-bool ApplicationIPCInterface::dbusRegister(AbstractApplication *app, QDBusConnection connection, const QString &debugPathPrefix)
+bool ApplicationIPCInterface::dbusRegister(Application *app, QDBusConnection connection, const QString &debugPathPrefix)
{
return m_ipcProxy ? m_ipcProxy->dbusRegister(app, connection, debugPathPrefix) : false;
}
@@ -432,7 +432,7 @@ QStringList IpcProxyObject::connectionNames() const
return m_connectionNamesToApplicationIds.keys();
}
-bool IpcProxyObject::isValidForApplication(AbstractApplication *app) const
+bool IpcProxyObject::isValidForApplication(Application *app) const
{
if (!app)
return false;
@@ -454,7 +454,7 @@ bool IpcProxyObject::isValidForApplication(AbstractApplication *app) const
#if defined(QT_DBUS_LIB)
-bool IpcProxyObject::dbusRegister(AbstractApplication *app, QDBusConnection connection, const QString &debugPathPrefix)
+bool IpcProxyObject::dbusRegister(Application *app, QDBusConnection connection, const QString &debugPathPrefix)
{
if (m_connectionNamesToApplicationIds.contains(connection.name()))
return false;
diff --git a/src/manager-lib/applicationipcinterface.h b/src/manager-lib/applicationipcinterface.h
index 3a1f8aad..bde98536 100644
--- a/src/manager-lib/applicationipcinterface.h
+++ b/src/manager-lib/applicationipcinterface.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -53,7 +53,7 @@
QT_BEGIN_NAMESPACE_AM
-class AbstractApplication;
+class Application;
class ApplicationIPCInterfaceAttached;
class IpcProxyObject;
@@ -70,12 +70,12 @@ public:
QString interfaceName() const;
QString pathName() const;
- bool isValidForApplication(AbstractApplication *app) const;
+ bool isValidForApplication(Application *app) const;
QObject *serviceObject() const;
void setServiceObject(QObject *serviceObject);
#if defined(QT_DBUS_LIB)
- bool dbusRegister(AbstractApplication *app, QDBusConnection connection, const QString &debugPathPrefix = QString());
+ bool dbusRegister(Application *app, QDBusConnection connection, const QString &debugPathPrefix = QString());
bool dbusUnregister(QDBusConnection connection);
#endif
diff --git a/src/manager-lib/applicationipcinterface_p.h b/src/manager-lib/applicationipcinterface_p.h
index e4828adb..d47c9ec8 100644
--- a/src/manager-lib/applicationipcinterface_p.h
+++ b/src/manager-lib/applicationipcinterface_p.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -54,7 +54,7 @@
QT_BEGIN_NAMESPACE_AM
-class AbstractApplication;
+class Application;
class IpcProxySignalRelay;
class IpcProxyObject // clazy:exclude=missing-qobject-macro
@@ -75,10 +75,10 @@ public:
QString interfaceName() const;
QStringList connectionNames() const;
- bool isValidForApplication(AbstractApplication *app) const;
+ bool isValidForApplication(Application *app) const;
#if defined(QT_DBUS_LIB)
- bool dbusRegister(AbstractApplication *app, QDBusConnection connection, const QString &debugPathPrefix = QString());
+ bool dbusRegister(Application *app, QDBusConnection connection, const QString &debugPathPrefix = QString());
bool dbusUnregister(QDBusConnection connection);
QString introspect(const QString &path) const override;
diff --git a/src/manager-lib/applicationipcmanager.cpp b/src/manager-lib/applicationipcmanager.cpp
index 2e0767f3..a4d375db 100644
--- a/src/manager-lib/applicationipcmanager.cpp
+++ b/src/manager-lib/applicationipcmanager.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/applicationipcmanager.h b/src/manager-lib/applicationipcmanager.h
index 427a6fef..856078b8 100644
--- a/src/manager-lib/applicationipcmanager.h
+++ b/src/manager-lib/applicationipcmanager.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/applicationmanager.cpp b/src/manager-lib/applicationmanager.cpp
index b5041055..5a391185 100644
--- a/src/manager-lib/applicationmanager.cpp
+++ b/src/manager-lib/applicationmanager.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -58,6 +59,7 @@
#include "global.h"
#include "applicationinfo.h"
+#include "installationreport.h"
#include "logging.h"
#include "exception.h"
#include "applicationmanager.h"
@@ -386,9 +388,9 @@ ApplicationManager *ApplicationManager::createInstance(bool singleProcess)
qmlRegisterSingletonType<ApplicationManager>("QtApplicationManager.SystemUI", 2, 0, "ApplicationManager",
&ApplicationManager::instanceForQml);
qmlRegisterType<ApplicationModel>("QtApplicationManager.SystemUI", 2, 0, "ApplicationModel");
- qmlRegisterUncreatableType<AbstractApplication>("QtApplicationManager.SystemUI", 2, 0, "ApplicationObject",
- qSL("Cannot create objects of type ApplicationObject"));
- qRegisterMetaType<AbstractApplication*>("AbstractApplication*");
+ qmlRegisterUncreatableType<Application>("QtApplicationManager.SystemUI", 2, 0, "ApplicationObject",
+ qSL("Cannot create objects of type ApplicationObject"));
+ qRegisterMetaType<Application*>("Application*");
qmlRegisterUncreatableType<AbstractRuntime>("QtApplicationManager.SystemUI", 2, 0, "Runtime",
qSL("Cannot create objects of type Runtime"));
qRegisterMetaType<AbstractRuntime*>("AbstractRuntime*");
@@ -497,27 +499,27 @@ void ApplicationManager::setWindowManagerCompositorReady(bool ready)
}
}
-QVector<AbstractApplication *> ApplicationManager::applications() const
+QVector<Application *> ApplicationManager::applications() const
{
return d->apps;
}
-AbstractApplication *ApplicationManager::fromId(const QString &id) const
+Application *ApplicationManager::fromId(const QString &id) const
{
- for (AbstractApplication *app : d->apps) {
+ for (Application *app : d->apps) {
if (app->id() == id)
return app;
}
return nullptr;
}
-AbstractApplication *ApplicationManager::fromProcessId(qint64 pid) const
+Application *ApplicationManager::fromProcessId(qint64 pid) const
{
// pid could be an indirect child (e.g. when started via gdbserver)
qint64 appmanPid = QCoreApplication::applicationPid();
while ((pid > 1) && (pid != appmanPid)) {
- for (AbstractApplication *app : d->apps) {
+ for (Application *app : d->apps) {
if (app->currentRuntime() && (app->currentRuntime()->applicationProcessId() == pid))
return app;
}
@@ -526,26 +528,23 @@ AbstractApplication *ApplicationManager::fromProcessId(qint64 pid) const
return nullptr;
}
-AbstractApplication *ApplicationManager::fromSecurityToken(const QByteArray &securityToken) const
+Application *ApplicationManager::fromSecurityToken(const QByteArray &securityToken) const
{
if (securityToken.size() != AbstractRuntime::SecurityTokenSize)
return nullptr;
- for (AbstractApplication *app : d->apps) {
+ for (Application *app : d->apps) {
if (app->currentRuntime() && app->currentRuntime()->securityToken() == securityToken)
return app;
}
return nullptr;
}
-QVector<AbstractApplication *> ApplicationManager::schemeHandlers(const QString &scheme) const
+QVector<Application *> ApplicationManager::schemeHandlers(const QString &scheme) const
{
- QVector<AbstractApplication *> handlers;
-
- for (AbstractApplication *app : d->apps) {
- if (app->isAlias())
- continue;
+ QVector<Application *> handlers;
+ for (Application *app : d->apps) {
const auto mimeTypes = app->supportedMimeTypes();
for (const QString &mime : mimeTypes) {
int pos = mime.indexOf(QLatin1Char('/'));
@@ -560,14 +559,11 @@ QVector<AbstractApplication *> ApplicationManager::schemeHandlers(const QString
return handlers;
}
-QVector<AbstractApplication *> ApplicationManager::mimeTypeHandlers(const QString &mimeType) const
+QVector<Application *> ApplicationManager::mimeTypeHandlers(const QString &mimeType) const
{
- QVector<AbstractApplication *> handlers;
-
- for (AbstractApplication *app : d->apps) {
- if (app->isAlias())
- continue;
+ QVector<Application *> handlers;
+ for (Application *app : d->apps) {
if (app->supportedMimeTypes().contains(mimeType))
handlers << app;
}
@@ -580,10 +576,7 @@ void ApplicationManager::registerMimeTypes()
QSet<QString> schemes;
schemes << qSL("file") << qSL("http") << qSL("https");
- for (AbstractApplication *app : qAsConst(d->apps)) {
- if (app->isAlias())
- continue;
-
+ for (Application *app : qAsConst(d->apps)) {
const auto mimeTypes = app->supportedMimeTypes();
for (const QString &mime : mimeTypes) {
int pos = mime.indexOf(QLatin1Char('/'));
@@ -613,14 +606,12 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS
{
if (d->shuttingDown)
throw Exception("Cannot start applications during shutdown");
- AbstractApplication *app = fromId(appId);
+ Application *app = fromId(appId);
if (!app)
throw Exception("Cannot start application: id '%1' is not known").arg(appId);
if (app->isBlocked())
throw Exception("Application %1 is blocked - cannot start").arg( app->id());
- Application* realApp = app->nonAliased();
-
AbstractRuntime *runtime = app->currentRuntime();
auto runtimeManager = runtime ? runtime->manager() : RuntimeFactory::instance()->manager(app->runtimeName());
if (!runtimeManager)
@@ -668,7 +659,6 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS
throw Exception("Application %1 is already running - cannot start with debug-wrapper: %2")
.arg(app->id(), debugWrapperSpecification);
}
-
if (!documentUrl.isNull())
runtime->openDocument(documentUrl, documentMimeType);
else if (!app->documentUrl().isNull())
@@ -731,8 +721,8 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS
else if (hasStdioRedirections)
cannotUseQuickLaunch = "standard I/O is redirected";
else if (!app->runtimeParameters().value(qSL("environmentVariables")).toMap().isEmpty())
- cannotUseQuickLaunch = "the app requests customs environment variables";
- else if (app->nonAliasedInfo()->openGLConfiguration() != runtimeManager->systemOpenGLConfiguration())
+ cannotUseQuickLaunch = "the app requests custom environment variables";
+ else if (app->info()->openGLConfiguration() != runtimeManager->systemOpenGLConfiguration())
cannotUseQuickLaunch = "the app requests a custom OpenGL configuration";
if (cannotUseQuickLaunch) {
@@ -741,12 +731,12 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS
} else {
// check quicklaunch pool
QPair<AbstractContainer *, AbstractRuntime *> quickLaunch =
- QuickLauncher::instance()->take(containerId, app->nonAliasedInfo()->runtimeName());
+ QuickLauncher::instance()->take(containerId, app->info()->runtimeName());
container = quickLaunch.first;
runtime = quickLaunch.second;
qCDebug(LogSystem) << "Found a quick-launch entry for container" << containerId
- << "and runtime" << app->nonAliasedInfo()->runtimeName() << "->" << container << runtime;
+ << "and runtime" << app->info()->runtimeName() << "->" << container << runtime;
if (!container && runtime) {
runtime->deleteLater();
@@ -769,7 +759,7 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS
attachRuntime = true;
}
if (!runtime)
- runtime = RuntimeFactory::instance()->create(container, realApp);
+ runtime = RuntimeFactory::instance()->create(container, app);
if (runtime)
emit internalSignals.newRuntimeCreated(runtime);
@@ -781,27 +771,9 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS
}
connect(runtime, &AbstractRuntime::stateChanged, this, [this, app](Am::RunState newRuntimeState) {
- QVector<AbstractApplication *> apps;
- //Always emit the actual starting app/alias first
- apps.append(app);
-
- //Add the original app and all aliases
- AbstractApplication *nonAliasedApp = app->nonAliased();
-
- if (!apps.contains(nonAliasedApp))
- apps.append(nonAliasedApp);
-
- for (AbstractApplication *alias : qAsConst(d->apps)) {
- if (!apps.contains(alias) && alias->isAlias() && alias->nonAliased() == nonAliasedApp)
- apps.append(alias);
- }
-
- static_cast<Application*>(nonAliasedApp)->setRunState(newRuntimeState);
-
- for (AbstractApplication *app : qAsConst(apps)) {
- emit applicationRunStateChanged(app->id(), newRuntimeState);
- emitDataChanged(app, QVector<int> { IsRunning, IsStartingUp, IsShuttingDown });
- }
+ app->setRunState(newRuntimeState);
+ emit applicationRunStateChanged(app->id(), newRuntimeState);
+ emitDataChanged(app, QVector<int> { IsRunning, IsStartingUp, IsShuttingDown });
});
if (!documentUrl.isNull())
@@ -826,11 +798,11 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS
// Using a state-machine would be one option, but then we would need that state-machine
// object plus the per-app state. Relying on 2 lambdas is the easier choice for now.
- auto doStartInContainer = [realApp, attachRuntime, runtime]() -> bool {
- bool successfullyStarted = attachRuntime ? runtime->attachApplicationToQuickLauncher(realApp)
+ auto doStartInContainer = [app, attachRuntime, runtime]() -> bool {
+ bool successfullyStarted = attachRuntime ? runtime->attachApplicationToQuickLauncher(app)
: runtime->start();
if (!successfullyStarted)
- runtime->deleteLater(); // ~Runtime() will clean realApp->m_runtime
+ runtime->deleteLater(); // ~Runtime() will clean app->m_runtime
return successfullyStarted;
};
@@ -866,7 +838,7 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS
}
}
-void ApplicationManager::stopApplicationInternal(AbstractApplication *app, bool forceKill)
+void ApplicationManager::stopApplicationInternal(Application *app, bool forceKill)
{
if (!app)
return;
@@ -950,12 +922,10 @@ void ApplicationManager::stopApplication(const QString &id, bool forceKill)
*/
void ApplicationManager::stopAllApplications(bool forceKill)
{
- for (AbstractApplication *app : qAsConst(d->apps)) {
- if (!app->isAlias()) {
- AbstractRuntime *rt = app->currentRuntime();
- if (rt)
- rt->stop(forceKill);
- }
+ for (Application *app : qAsConst(d->apps)) {
+ AbstractRuntime *rt = app->currentRuntime();
+ if (rt)
+ rt->stop(forceKill);
}
}
@@ -1000,6 +970,8 @@ void ApplicationManager::stopAllApplications(bool forceKill)
*/
bool ApplicationManager::openUrl(const QString &urlStr)
{
+ //TODO: relay to a well-known Intent call
+
// QDesktopServices::openUrl has a special behavior when called recursively, which makes sense
// on the desktop, but is completely counter-productive for the AM.
static bool recursionGuard = false;
@@ -1011,28 +983,13 @@ bool ApplicationManager::openUrl(const QString &urlStr)
QUrl url(urlStr);
QString mimeTypeName;
- QVector<AbstractApplication *> apps;
+ QVector<Application *> apps;
if (url.isValid()) {
QString scheme = url.scheme();
- if (scheme != qL1S("file")) {
+ if (scheme != qL1S("file"))
apps = schemeHandlers(scheme);
- for (auto it = apps.begin(); it != apps.end(); ++it) {
- AbstractApplication *&app = *it;
-
- // try to find a better matching alias, if available
- for (AbstractApplication *alias : d->apps) {
- if (alias->isAlias() && alias->nonAliased() == app) {
- if (url.toString(QUrl::PrettyDecoded) == alias->documentUrl()) {
- app = alias;
- break;
- }
- }
- }
- }
- }
-
if (apps.isEmpty()) {
QMimeDatabase mdb;
QMimeType mt = mdb.mimeTypeForUrl(url);
@@ -1054,9 +1011,9 @@ bool ApplicationManager::openUrl(const QString &urlStr)
} else {
ApplicationManagerPrivate::OpenUrlRequest req {
QUuid::createUuid().toString(),
- urlStr,
- mimeTypeName,
- QStringList()
+ urlStr,
+ mimeTypeName,
+ QStringList()
};
for (const auto &app : qAsConst(apps))
req.possibleAppIds << app->id();
@@ -1149,7 +1106,7 @@ void ApplicationManager::rejectOpenUrlRequest(const QString &requestId)
*/
QStringList ApplicationManager::capabilities(const QString &id) const
{
- AbstractApplication *app = fromId(id);
+ Application *app = fromId(id);
return app ? app->capabilities() : QStringList();
}
@@ -1163,246 +1120,10 @@ QStringList ApplicationManager::capabilities(const QString &id) const
*/
QString ApplicationManager::identifyApplication(qint64 pid) const
{
- AbstractApplication *app = fromProcessId(pid);
+ Application *app = fromProcessId(pid);
return app ? app->id() : QString();
}
-bool ApplicationManager::blockApplication(const QString &id)
-{
- AbstractApplication *app = fromId(id);
- if (!app)
- return false;
- if (!app->block())
- return false;
- emitDataChanged(app, QVector<int> { IsBlocked });
- stopApplicationInternal(app, true);
- emitDataChanged(app, QVector<int> { IsRunning });
- return true;
-}
-
-bool ApplicationManager::unblockApplication(const QString &id)
-{
- AbstractApplication *app = fromId(id);
- if (!app)
- return false;
- if (!app->unblock())
- return false;
- emitDataChanged(app, QVector<int> { IsBlocked });
- return true;
-}
-
-bool ApplicationManager::startingApplicationInstallation(ApplicationInfo *info)
-{
- // ownership of info is transferred to ApplicationManager
- QScopedPointer<ApplicationInfo> newInfo(info);
-
- if (!newInfo || newInfo->id().isEmpty())
- return false;
- AbstractApplication *absApp = fromId(newInfo->id());
- if (!RuntimeFactory::instance()->manager(newInfo->runtimeName()))
- return false;
-
- if (absApp) { // update
- Q_ASSERT(!absApp->isAlias());
- Application *app = static_cast<Application*>(absApp);
-
- if (!blockApplication(app->id()))
- return false;
-
- // There is still an issue with "shadowing" built-in apps (which will be properly fixed in 5.14):
- // As the updatedInfo might be used already (by an already updated built-in app), we cannot revert back any
- // more to the previous version. Canceling the update will therefore revert back to the original app.
- app->setUpdatedInfo(newInfo.take());
- app->setState(Application::BeingUpdated);
- app->setProgress(0);
- emitDataChanged(app);
- } else { // installation
- Application *app = new Application(newInfo.take(), Application::BeingInstalled);
-
- app->block();
-
- beginInsertRows(QModelIndex(), d->apps.count(), d->apps.count());
- addApplication(app);
- endInsertRows();
-
- emitDataChanged(app);
-
- emit applicationAdded(app->id());
- }
- return true;
-}
-
-bool ApplicationManager::startingApplicationRemoval(const QString &id)
-{
- AbstractApplication *absApp = fromId(id);
- if (!absApp)
- return false;
-
- Q_ASSERT(!absApp->isAlias());
-
- Application *app = static_cast<Application*>(absApp);
- if (app->isBlocked() || (app->state() != Application::Installed))
- return false;
-
- if (app->isBuiltIn() && !app->updatedInfo())
- return false;
-
- if (!blockApplication(id))
- return false;
-
- if (app->updatedInfo())
- app->setState(Application::BeingDowngraded);
- else
- app->setState(Application::BeingRemoved);
-
- app->setProgress(0);
- emitDataChanged(app, QVector<int> { IsUpdating });
- return true;
-}
-
-void ApplicationManager::progressingApplicationInstall(const QString &id, qreal progress)
-{
- AbstractApplication *absApp = fromId(id);
- if (!absApp)
- return;
-
- Q_ASSERT(!absApp->isAlias());
- Application *app = static_cast<Application*>(absApp);
-
- if (app->state() == Application::Installed)
- return;
- app->setProgress(progress);
- // Icon will be in a "+" suffixed directory during installation. So notify about a change on its
- // location as well.
- emitDataChanged(app, QVector<int> { Icon, UpdateProgress });
-}
-
-bool ApplicationManager::finishedApplicationInstall(const QString &id)
-{
- AbstractApplication *absApp = fromId(id);
- if (!absApp)
- return false;
-
- Q_ASSERT(!absApp->isAlias());
- Application *app = static_cast<Application*>(absApp);
-
- switch (app->state()) {
- case Application::Installed:
- return false;
-
- case Application::BeingUpdated:
- if (!static_cast<ApplicationInfo*>(app->baseInfo())->isBuiltIn())
- app->setBaseInfo(app->takeUpdatedInfo());
- Q_FALLTHROUGH();
- case Application::BeingInstalled: {
- // The Application object has been updated right at the start of the installation/update.
- // Now's the time to update the InstallationReport that was written by the installer.
- QFile irfile(QDir(app->nonAliasedInfo()->manifestDir()).absoluteFilePath(qSL("installation-report.yaml")));
- QScopedPointer<InstallationReport> ir(new InstallationReport(app->id()));
- if (!irfile.open(QFile::ReadOnly) || !ir->deserialize(&irfile)) {
- qCCritical(LogInstaller) << "Could not read the new installation-report for application"
- << app->id() << "at" << irfile.fileName();
- return false;
- }
- app->nonAliasedInfo()->setInstallationReport(ir.take());
- registerMimeTypes();
- app->setState(Application::Installed);
- app->setProgress(0);
-
- emitDataChanged(app);
-
- unblockApplication(id);
- emit app->bulkChange(); // not ideal, but icon and codeDir have changed
- break;
- }
- case Application::BeingDowngraded:
- app->setUpdatedInfo(nullptr);
- app->setState(Application::Installed);
- registerMimeTypes();
- emitDataChanged(app);
- unblockApplication(id);
- break;
- case Application::BeingRemoved: {
- int row = d->apps.indexOf(app);
- if (row >= 0) {
- emit applicationAboutToBeRemoved(app->id());
- beginRemoveRows(QModelIndex(), row, row);
- d->apps.removeAt(row);
- endRemoveRows();
- }
- delete app;
- registerMimeTypes();
- break;
- }
- }
-
- emit internalSignals.applicationsChanged();
-
- return true;
-}
-
-bool ApplicationManager::canceledApplicationInstall(const QString &id)
-{
- AbstractApplication *absApp = fromId(id);
- if (!absApp)
- return false;
-
- Q_ASSERT(!absApp->isAlias());
- Application *app = static_cast<Application*>(absApp);
-
- switch (app->state()) {
- case Application::Installed:
- return false;
-
- case Application::BeingInstalled: {
- int row = d->apps.indexOf(app);
- if (row >= 0) {
- emit applicationAboutToBeRemoved(app->id());
- beginRemoveRows(QModelIndex(), row, row);
- d->apps.removeAt(row);
- endRemoveRows();
- }
- delete app;
- break;
- }
- case Application::BeingUpdated:
- app->setUpdatedInfo(nullptr);
- Q_FALLTHROUGH();
- case Application::BeingDowngraded:
- case Application::BeingRemoved:
- app->setState(Application::Installed);
- app->setProgress(0);
- emitDataChanged(app);
-
- unblockApplication(id);
- break;
- }
- return true;
-}
-
-void ApplicationManager::enableSingleAppMode()
-{
- QMetaObject::invokeMethod(this, &ApplicationManager::startSingleAppAndQuitWhenStopped, Qt::QueuedConnection);
-}
-
-void ApplicationManager::startSingleAppAndQuitWhenStopped()
-{
- Q_ASSERT(d->apps.count() == 1);
-
- AbstractApplication *app = d->apps[0];
-
- if (!startApplication(app->id())) {
- QMetaObject::invokeMethod(qApp, "shutDown", Qt::DirectConnection, Q_ARG(int, 1));
- } else {
- connect(this, &ApplicationManager::applicationRunStateChanged, [app](const QString &id, Am::RunState runState) {
- if ((id == app->id()) && (runState == Am::NotRunning)) {
- QMetaObject::invokeMethod(qApp, "shutDown", Qt::DirectConnection,
- Q_ARG(int, app->lastExitCode()));
- }
- });
- }
-}
-
void ApplicationManager::shutDown()
{
d->shuttingDown = true;
@@ -1410,7 +1131,7 @@ void ApplicationManager::shutDown()
auto shutdownHelper = [this]() {
bool activeRuntime = false;
- for (AbstractApplication *app : qAsConst(d->apps)) {
+ for (Application *app : qAsConst(d->apps)) {
AbstractRuntime *rt = app->currentRuntime();
if (rt) {
activeRuntime = true;
@@ -1421,7 +1142,7 @@ void ApplicationManager::shutDown()
emit shutDownFinished();
};
- for (AbstractApplication *app : qAsConst(d->apps)) {
+ for (Application *app : qAsConst(d->apps)) {
AbstractRuntime *rt = app->currentRuntime();
if (rt) {
connect(rt, &AbstractRuntime::destroyed,
@@ -1441,7 +1162,7 @@ void ApplicationManager::openUrlRelay(const QUrl &url)
openUrl(url.toString());
}
-void ApplicationManager::emitDataChanged(AbstractApplication *app, const QVector<int> &roles)
+void ApplicationManager::emitDataChanged(Application *app, const QVector<int> &roles)
{
int row = d->apps.indexOf(app);
if (row >= 0) {
@@ -1457,9 +1178,9 @@ void ApplicationManager::emitDataChanged(AbstractApplication *app, const QVector
}
}
-void ApplicationManager::emitActivated(AbstractApplication *app)
+void ApplicationManager::emitActivated(Application *app)
{
- emit applicationWasActivated(app->isAlias() ? app->nonAliased()->id() : app->id(), app->id());
+ emit applicationWasActivated(app->id(), app->id());
emit app->activated();
}
@@ -1477,29 +1198,15 @@ QVariant ApplicationManager::data(const QModelIndex &index, int role) const
if (index.parent().isValid() || !index.isValid())
return QVariant();
- AbstractApplication *app = d->apps.at(index.row());
+ Application *app = d->apps.at(index.row());
switch (role) {
case Id:
return app->id();
- case Name: {
- QString name;
- if (!app->info()->names().isEmpty()) {
- name = app->info()->name(d->currentLocale);
- if (name.isEmpty())
- name = app->info()->name(qSL("en"));
- if (name.isEmpty())
- name = app->info()->name(qSL("en_US"));
- if (name.isEmpty())
- name = *app->info()->names().constBegin();
- } else {
- name = app->id();
- }
- return name;
- }
+ case Name:
+ return app->name();
case Icon:
return app->icon();
-
case IsRunning:
return app->currentRuntime() ? (app->currentRuntime()->state() == Am::Running) : false;
case IsStartingUp:
@@ -1514,9 +1221,8 @@ QVariant ApplicationManager::data(const QModelIndex &index, int role) const
return app->progress();
case IsRemovable:
return !app->isBuiltIn();
-
case CodeFilePath:
- return app->nonAliasedInfo()->absoluteCodeFilePath();
+ return app->info()->absoluteCodeFilePath();
case RuntimeName:
return app->runtimeName();
case RuntimeParameters:
@@ -1583,7 +1289,7 @@ QVariantMap ApplicationManager::get(int index) const
signals or the applicationAboutToBeRemoved signal to get notified if the object is about
to be deleted on the C++ side.
*/
-AbstractApplication *ApplicationManager::application(int index) const
+Application *ApplicationManager::application(int index) const
{
if (index < 0 || index >= count()) {
qCWarning(LogSystem) << "ApplicationManager::application(index): invalid index:" << index;
@@ -1603,7 +1309,7 @@ AbstractApplication *ApplicationManager::application(int index) const
signals or the applicationAboutToBeRemoved signal to get notified if the object is about
to be deleted on the C++ side.
*/
-AbstractApplication *ApplicationManager::application(const QString &id) const
+Application *ApplicationManager::application(const QString &id) const
{
auto index = indexOfApplication(id);
return (index < 0) ? nullptr : application(index);
@@ -1612,9 +1318,8 @@ AbstractApplication *ApplicationManager::application(const QString &id) const
/*!
\qmlmethod int ApplicationManager::indexOfApplication(string id)
- Maps the application \a id to its position within the model.
-
- Returns \c -1 if the specified \a id is invalid.
+ Maps the application corresponding to the given \a id to its position within the model. Returns
+ \c -1 if the specified \a id is invalid.
*/
int ApplicationManager::indexOfApplication(const QString &id) const
{
@@ -1626,6 +1331,17 @@ int ApplicationManager::indexOfApplication(const QString &id) const
}
/*!
+ \qmlmethod int ApplicationManager::indexOfApplication(ApplicationObject application)
+
+ Maps the \a application to its position within this model. Returns \c -1 if the specified
+ application is invalid.
+*/
+int ApplicationManager::indexOfApplication(Application *application) const
+{
+ return d->apps.indexOf(application);
+}
+
+/*!
\qmlmethod list<string> ApplicationManager::applicationIds()
Returns a list of all available application ids. This can be used to further query for specific
@@ -1660,16 +1376,18 @@ Am::RunState ApplicationManager::applicationRunState(const QString &id) const
return (index < 0) ? Am::NotRunning : d->apps.at(index)->runState();
}
-void ApplicationManager::setApplications(const QVector<AbstractApplication *> &apps)
+void ApplicationManager::addApplication(ApplicationInfo *appInfo, Package *package)
{
- Q_ASSERT(d->apps.count() == 0);
- for (auto app : apps)
- addApplication(app);
- registerMimeTypes();
-}
+ // check for id clashes outside of the package (the scanner made sure the package itself is
+ // consistent and doesn't have duplicates already)
+ for (Application *checkApp : qAsConst(d->apps)) {
+ if ((checkApp->id() == appInfo->id()) && (checkApp->package() != package)) {
+ throw Exception("found an application with the same id in package %1")
+ .arg(checkApp->packageInfo()->id());
+ }
+ }
-void ApplicationManager::addApplication(AbstractApplication *app)
-{
+ auto app = new Application(appInfo, package);
QQmlEngine::setObjectOwnership(app, QQmlEngine::CppOwnership);
app->requests.startRequested = [this, app](const QString &documentUrl) {
@@ -1684,7 +1402,49 @@ void ApplicationManager::addApplication(AbstractApplication *app)
stopApplication(app->id(), forceKill);
};
+ connect(app, &Application::blockedChanged,
+ this, [this, app]() {
+ emitDataChanged(app, QVector<int> { IsBlocked });
+ });
+ connect(app, &Application::bulkChange,
+ this, [this, app]() {
+ emitDataChanged(app);
+ });
+
+ beginInsertRows(QModelIndex(), d->apps.count(), d->apps.count());
d->apps << app;
+
+ endInsertRows();
+
+ registerMimeTypes();
+ emit applicationAdded(appInfo->id());
+}
+
+void ApplicationManager::removeApplication(ApplicationInfo *appInfo, Package *package)
+{
+ int index = -1;
+
+ for (int i = 0; i < d->apps.size(); ++i) {
+ if (d->apps.at(i)->info() == appInfo) {
+ index = i;
+ break;
+ }
+ }
+ if (index < 0)
+ return;
+
+ Q_ASSERT(d->apps.at(index)->package() == package);
+
+ emit applicationAboutToBeRemoved(appInfo->id());
+
+ beginRemoveRows(QModelIndex(), index, index);
+ auto app = d->apps.takeAt(index);
+
+ endRemoveRows();
+
+ registerMimeTypes();
+
+ delete app;
}
QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/applicationmanager.h b/src/manager-lib/applicationmanager.h
index 60b133dd..d7d8f0fa 100644
--- a/src/manager-lib/applicationmanager.h
+++ b/src/manager-lib/applicationmanager.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -65,8 +66,6 @@ class ApplicationManagerInternalSignals : public QObject
{
Q_OBJECT
signals:
- // Emitted after an application is installed, updated, downgraded or removed
- void applicationsChanged();
// Emitted every time a new Runtime object is created
void newRuntimeCreated(QT_PREPEND_NAMESPACE_AM(AbstractRuntime) *runtime);
};
@@ -98,24 +97,21 @@ public:
QVariantMap systemProperties() const;
void setSystemProperties(const QVariantMap &map);
- // Set the initial application list
- // To be used only during startup (ie, before exposing ApplicationManager to QML) as
- // no model update signals are emitted.
- void setApplications(const QVector<AbstractApplication *> &apps);
+ void addApplication(ApplicationInfo *appInfo, Package *package);
+ void removeApplication(ApplicationInfo *appInfo, Package *package);
+ QVector<Application *> applications() const;
- QVector<AbstractApplication *> applications() const;
-
- AbstractApplication *fromId(const QString &id) const;
- AbstractApplication *fromProcessId(qint64 pid) const;
- AbstractApplication *fromSecurityToken(const QByteArray &securityToken) const;
- QVector<AbstractApplication *> schemeHandlers(const QString &scheme) const;
- QVector<AbstractApplication *> mimeTypeHandlers(const QString &mimeType) const;
+ Application *fromId(const QString &id) const;
+ Application *fromProcessId(qint64 pid) const;
+ Application *fromSecurityToken(const QByteArray &securityToken) const;
+ QVector<Application *> schemeHandlers(const QString &scheme) const;
+ QVector<Application *> mimeTypeHandlers(const QString &mimeType) const;
bool startApplicationInternal(const QString &appId, const QString &documentUrl = QString(),
const QString &documentMimeType = QString(),
const QString &debugWrapperSpecification = QString(),
const QVector<int> &stdioRedirections = QVector<int>()) Q_DECL_NOEXCEPT_EXPR(false);
- void stopApplicationInternal(AbstractApplication *app, bool forceKill = false);
+ void stopApplicationInternal(Application *app, bool forceKill = false);
// only use these two functions for development!
bool securityChecksEnabled() const;
@@ -137,9 +133,10 @@ public:
int count() const;
Q_INVOKABLE QVariantMap get(int index) const;
- Q_INVOKABLE AbstractApplication *application(int index) const;
- Q_INVOKABLE AbstractApplication *application(const QString &id) const;
+ Q_INVOKABLE Application *application(int index) const;
+ Q_INVOKABLE Application *application(const QString &id) const;
Q_INVOKABLE int indexOfApplication(const QString &id) const;
+ Q_INVOKABLE int indexOfApplication(Application *application) const;
Q_INVOKABLE void acknowledgeOpenUrlRequest(const QString &requestId, const QString &appId);
Q_INVOKABLE void rejectOpenUrlRequest(const QString &requestId);
@@ -158,8 +155,6 @@ public:
ApplicationManagerInternalSignals internalSignals;
- void enableSingleAppMode();
-
public slots:
void shutDown();
@@ -183,29 +178,11 @@ signals:
void windowManagerCompositorReadyChanged(bool ready);
private slots:
- void startSingleAppAndQuitWhenStopped();
void openUrlRelay(const QUrl &url);
- void addApplication(AbstractApplication *app);
-
- // Interface for the installer
- //TODO: Find something nicer than private slots with 3 friend classes.
- // This is hard though, since the senders live in different threads and
- // need to use BlockingQueuedConnections
- bool blockApplication(const QString &id);
- bool unblockApplication(const QString &id);
- bool startingApplicationInstallation(QT_PREPEND_NAMESPACE_AM(ApplicationInfo*) installApp);
- bool startingApplicationRemoval(const QString &id);
- void progressingApplicationInstall(const QString &id, qreal progress);
- bool finishedApplicationInstall(const QString &id);
- bool canceledApplicationInstall(const QString &id);
-
- friend class ApplicationInstaller;
- friend class InstallationTask;
- friend class DeinstallationTask;
private:
- void emitDataChanged(AbstractApplication *app, const QVector<int> &roles = QVector<int>());
- void emitActivated(AbstractApplication *app);
+ void emitDataChanged(Application *app, const QVector<int> &roles = QVector<int>());
+ void emitActivated(Application *app);
void registerMimeTypes();
ApplicationManager(bool singleProcess, QObject *parent = nullptr);
diff --git a/src/manager-lib/applicationmanager_p.h b/src/manager-lib/applicationmanager_p.h
index c9d1ad6b..5ba28b3d 100644
--- a/src/manager-lib/applicationmanager_p.h
+++ b/src/manager-lib/applicationmanager_p.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -60,7 +61,7 @@ public:
bool windowManagerCompositorReady = false;
QVariantMap systemProperties;
- QVector<AbstractApplication *> apps;
+ QVector<Application *> apps;
QString currentLocale;
QHash<int, QByteArray> roleNames;
diff --git a/src/manager-lib/applicationmodel.cpp b/src/manager-lib/applicationmodel.cpp
index 5fd46ebd..4deed932 100644
--- a/src/manager-lib/applicationmodel.cpp
+++ b/src/manager-lib/applicationmodel.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -42,10 +43,12 @@
#include <QQmlContext>
#include <QQmlEngine>
+#include <QQmlInfo>
#include <QJSEngine>
#include <QJSValueList>
#include "global.h"
+#include "logging.h"
#include "applicationmanager.h"
#include "applicationmodel.h"
#include "application.h"
@@ -105,6 +108,9 @@
If the application passed should be included in this model, then the function must return
\c true; \c false otherwise.
+ If you need no filtering at all, you should set this property to an undefined (the default) or
+ null value.
+
\note Whenever this function is changed, the filter is reevaluated. However, dynamic properties
used in this function, like \c isRunning, don't trigger a reevaluation when those properties
change. Changes in the source model are reflected. Since the type is derived from
@@ -120,6 +126,9 @@
application should have a smaller index in this model than the second, the function must return
\c true; \c false otherwise.
+ If you need no sorting at all, you should set this property to an undefined (the default) or
+ null value.
+
\note Whenever this function is changed, the model is sorted. However, dynamic properties
used in this function, like \c isRunning, don't trigge a sort when when those properties change.
Changes in the source model are reflected. Since the type is derived from
@@ -140,8 +149,9 @@ public:
};
-ApplicationModel::ApplicationModel()
- : d(new ApplicationModelPrivate())
+ApplicationModel::ApplicationModel(QObject *parent)
+ : QSortFilterProxyModel(parent)
+ , d(new ApplicationModelPrivate())
{
setSourceModel(ApplicationManager::instance());
@@ -162,6 +172,8 @@ bool ApplicationModel::filterAcceptsRow(int source_row, const QModelIndex &sourc
if (!d->m_engine)
d->m_engine = getJSEngine();
+ if (!d->m_engine)
+ qCWarning(LogSystem) << "ApplicationModel can't filter without a JavaScript engine";
if (d->m_engine && d->m_filterFunction.isCallable()) {
const QObject *app = ApplicationManager::instance()->application(source_row);
@@ -176,6 +188,8 @@ bool ApplicationModel::lessThan(const QModelIndex &source_left, const QModelInde
{
if (!d->m_engine)
d->m_engine = getJSEngine();
+ if (!d->m_engine)
+ qCWarning(LogSystem) << "ApplicationModel can't sort without a JavaScript engine";
if (d->m_engine && d->m_sortFunction.isCallable()) {
const QObject *app1 = ApplicationManager::instance()->application(source_left.row());
@@ -195,6 +209,10 @@ QJSValue ApplicationModel::filterFunction() const
void ApplicationModel::setFilterFunction(const QJSValue &callback)
{
+ if (!callback.isCallable() && !callback.isNull() && !callback.isUndefined()) {
+ qmlWarning(this) << "The filterFunction property of ApplicationModel needs to be either "
+ "callable, or undefined/null to clear it.";
+ }
if (!callback.equals(d->m_filterFunction)) {
d->m_filterFunction = callback;
emit filterFunctionChanged();
@@ -209,6 +227,10 @@ QJSValue ApplicationModel::sortFunction() const
void ApplicationModel::setSortFunction(const QJSValue &callback)
{
+ if (!callback.isCallable() && !callback.isNull() && !callback.isUndefined()) {
+ qmlWarning(this) << "The sortFunction property of ApplicationModel needs to be either "
+ "callable, or undefined/null to clear it.";
+ }
if (!callback.equals(d->m_sortFunction)) {
d->m_sortFunction = callback;
emit sortFunctionChanged();
@@ -220,8 +242,8 @@ void ApplicationModel::setSortFunction(const QJSValue &callback)
/*!
\qmlmethod int ApplicationModel::indexOfApplication(string id)
- Maps the application \a id to its position within this model. Returns \c -1 if the specified
- \a id is invalid, or not part of this model.
+ Maps the application corresponding to the given \a id to its position within this model. Returns
+ \c -1 if the specified application is invalid, or not part of this model.
*/
int ApplicationModel::indexOfApplication(const QString &id) const
{
@@ -230,6 +252,18 @@ int ApplicationModel::indexOfApplication(const QString &id) const
}
/*!
+ \qmlmethod int ApplicationModel::indexOfApplication(ApplicationObject application)
+
+ Maps the \a application to its position within this model. Returns \c -1 if the specified
+ application is invalid, or not part of this model.
+*/
+int ApplicationModel::indexOfApplication(Application *application) const
+{
+ int idx = ApplicationManager::instance()->indexOfApplication(application);
+ return idx != -1 ? mapFromSource(idx) : idx;
+}
+
+/*!
\qmlmethod int ApplicationModel::mapToSource(int index)
Maps an application's \a index in this model to the corresponding index in the
diff --git a/src/manager-lib/applicationmodel.h b/src/manager-lib/applicationmodel.h
index 5cedb69a..6d0ef279 100644
--- a/src/manager-lib/applicationmodel.h
+++ b/src/manager-lib/applicationmodel.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -51,6 +52,7 @@ QT_FORWARD_DECLARE_CLASS(QJSEngine);
QT_BEGIN_NAMESPACE_AM
class ApplicationModelPrivate;
+class Application;
class ApplicationModel : public QSortFilterProxyModel
{
@@ -62,7 +64,7 @@ class ApplicationModel : public QSortFilterProxyModel
Q_PROPERTY(QJSValue sortFunction READ sortFunction WRITE setSortFunction NOTIFY sortFunctionChanged)
public:
- ApplicationModel();
+ ApplicationModel(QObject *parent = nullptr);
int count() const;
@@ -73,6 +75,7 @@ public:
void setSortFunction(const QJSValue &callback);
Q_INVOKABLE int indexOfApplication(const QString &id) const;
+ Q_INVOKABLE int indexOfApplication(Application *application) const;
Q_INVOKABLE int mapToSource(int ourIndex) const;
Q_INVOKABLE int mapFromSource(int sourceIndex) const;
diff --git a/src/installer-lib/asynchronoustask.cpp b/src/manager-lib/asynchronoustask.cpp
index 53406e0f..4b1b9e67 100644
--- a/src/installer-lib/asynchronoustask.cpp
+++ b/src/manager-lib/asynchronoustask.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -103,9 +103,19 @@ bool AsynchronousTask::forceCancel()
return cancel();
}
-QString AsynchronousTask::applicationId() const
+QString AsynchronousTask::packageId() const
{
- return m_applicationId;
+ return m_packageId;
+}
+
+bool AsynchronousTask::preExecute()
+{
+ return true;
+}
+
+bool AsynchronousTask::postExecute()
+{
+ return true;
}
void AsynchronousTask::setError(Error errorCode, const QString &errorString)
diff --git a/src/installer-lib/asynchronoustask.h b/src/manager-lib/asynchronoustask.h
index 86b661c2..5ad8714f 100644
--- a/src/installer-lib/asynchronoustask.h
+++ b/src/manager-lib/asynchronoustask.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -83,7 +83,10 @@ public:
virtual bool cancel();
bool forceCancel(); // will always work in Queued state
- QString applicationId() const; // convenience
+ QString packageId() const; // convenience
+
+ virtual bool preExecute();
+ virtual bool postExecute();
signals:
void stateChanged(QT_PREPEND_NAMESPACE_AM(AsynchronousTask::TaskState) newState);
@@ -98,10 +101,11 @@ protected:
QMutex m_mutex;
QString m_id;
- QString m_applicationId;
+ QString m_packageId;
TaskState m_state = Queued;
Error m_errorCode = Error::None;
QString m_errorString;
};
+
QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/containerfactory.cpp b/src/manager-lib/containerfactory.cpp
index fbeb2e49..c8ff91c0 100644
--- a/src/manager-lib/containerfactory.cpp
+++ b/src/manager-lib/containerfactory.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -83,7 +83,7 @@ AbstractContainerManager *ContainerFactory::manager(const QString &id)
return m_containers.value(id);
}
-AbstractContainer *ContainerFactory::create(const QString &id, AbstractApplication *app,
+AbstractContainer *ContainerFactory::create(const QString &id, Application *app,
const QVector<int> &stdioRedirections,
const QMap<QString, QString> &debugWrapperEnvironment,
const QStringList &debugWrapperCommand)
diff --git a/src/manager-lib/containerfactory.h b/src/manager-lib/containerfactory.h
index 020100d8..102c094c 100644
--- a/src/manager-lib/containerfactory.h
+++ b/src/manager-lib/containerfactory.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -49,7 +49,7 @@
QT_BEGIN_NAMESPACE_AM
-class AbstractApplication;
+class Application;
class AbstractContainer;
class AbstractContainerManager;
@@ -64,7 +64,7 @@ public:
QStringList containerIds() const;
AbstractContainerManager *manager(const QString &id);
- AbstractContainer *create(const QString &id, AbstractApplication *app,
+ AbstractContainer *create(const QString &id, Application *app,
const QVector<int> &stdioRedirections = QVector<int>(),
const QMap<QString, QString> &debugWrapperEnvironment = QMap<QString, QString>(),
const QStringList &debugWrapperCommand = QStringList());
diff --git a/src/manager-lib/debugwrapper.cpp b/src/manager-lib/debugwrapper.cpp
index 59eb582e..bb1fc4c3 100644
--- a/src/manager-lib/debugwrapper.cpp
+++ b/src/manager-lib/debugwrapper.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/debugwrapper.h b/src/manager-lib/debugwrapper.h
index fdfd33f0..14060334 100644
--- a/src/manager-lib/debugwrapper.h
+++ b/src/manager-lib/debugwrapper.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/installer-lib/deinstallationtask.cpp b/src/manager-lib/deinstallationtask.cpp
index 8f31e3ee..4695add6 100644
--- a/src/installer-lib/deinstallationtask.cpp
+++ b/src/manager-lib/deinstallationtask.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -41,26 +41,27 @@
****************************************************************************/
#include "logging.h"
-#include "applicationinstaller.h"
-#include "applicationinstaller_p.h"
-#include "applicationmanager.h"
+#include "packagemanager.h"
+#include "packagemanager_p.h"
#include "installationreport.h"
-#include "applicationinfo.h"
+#include "package.h"
#include "exception.h"
#include "scopeutilities.h"
#include "deinstallationtask.h"
QT_BEGIN_NAMESPACE_AM
-DeinstallationTask::DeinstallationTask(ApplicationInfo *app, const InstallationLocation &installationLocation,
- bool forceDeinstallation, bool keepDocuments, QObject *parent)
+DeinstallationTask::DeinstallationTask(Package *package, const QString &installationPath,
+ const QString &documentPath, bool forceDeinstallation,
+ bool keepDocuments, QObject *parent)
: AsynchronousTask(parent)
- , m_app(app)
- , m_installationLocation(installationLocation)
+ , m_package(package)
+ , m_installationPath(installationPath)
+ , m_documentPath(documentPath)
, m_forceDeinstallation(forceDeinstallation)
, m_keepDocuments(keepDocuments)
{
- m_applicationId = m_app->id(); // in base class
+ m_packageId = m_package->id(); // in base class
}
bool DeinstallationTask::cancel()
@@ -72,30 +73,28 @@ bool DeinstallationTask::cancel()
void DeinstallationTask::execute()
{
- // these have been checked in ApplicationInstaller::removePackage() already
- Q_ASSERT(m_app);
- Q_ASSERT(m_app->installationReport());
- Q_ASSERT(m_app->installationReport()->installationLocationId() == m_installationLocation.id());
- Q_ASSERT(m_installationLocation.isValid());
+ // these have been checked in PackageManager::removePackage() already
+ Q_ASSERT(m_package);
+ Q_ASSERT(m_package->info());
+ Q_ASSERT(m_package->info()->installationReport());
bool managerApproval = false;
try {
- // we need to call those ApplicationManager methods in the correct thread
- // this will also exclusively lock the application for us
- QMetaObject::invokeMethod(ApplicationManager::instance(),
- "startingApplicationRemoval",
- Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(bool, managerApproval),
- Q_ARG(QString, m_app->id()));
+ // we need to call those PackageManager methods in the correct thread
+ // this will also exclusively lock the package for us
+ QMetaObject::invokeMethod(PackageManager::instance(), [this, &managerApproval]()
+ { managerApproval = PackageManager::instance()->startingPackageRemoval(m_package->id()); },
+ Qt::BlockingQueuedConnection);
+
if (!managerApproval)
- throw Exception("ApplicationManager rejected the removal of app %1").arg(m_app->id());
+ throw Exception("PackageManager rejected the removal of package %1").arg(m_package->id());
- // if the app was running before, we now need to wait until is has actually stopped
- while (!m_canceled &&
- (ApplicationManager::instance()->applicationRunState(m_app->id()) != Am::NotRunning)) {
+ // if any of the apps in the package were running before, we now need to wait until all of
+ // them have actually stopped
+ while (!m_canceled && !m_package->areAllApplicationsStoppedDueToBlock())
QThread::msleep(30);
- }
+
// there's a small race condition here, but not doing a planned cancellation isn't harmful
m_canBeCanceled = false;
if (m_canceled)
@@ -103,59 +102,50 @@ void DeinstallationTask::execute()
ScopedRenamer docDirRename;
ScopedRenamer appDirRename;
- ScopedRenamer manifestRename;
if (!m_keepDocuments) {
- if (!docDirRename.rename(QDir(m_installationLocation.documentPath()).absoluteFilePath(m_app->id()),
+ if (!docDirRename.rename(QDir(m_documentPath).absoluteFilePath(m_package->id()),
ScopedRenamer::NameToNameMinus)) {
throw Exception(Error::IO, "could not rename %1 to %1-").arg(docDirRename.baseName());
}
}
- if (!appDirRename.rename(QDir(m_installationLocation.installationPath()).absoluteFilePath(m_app->id()),
+ if (!appDirRename.rename(QDir(m_installationPath).absoluteFilePath(m_package->id()),
ScopedRenamer::NameToNameMinus)) {
throw Exception(Error::IO, "could not rename %1 to %1-").arg(appDirRename.baseName());
}
- if (!manifestRename.rename(ApplicationInstaller::instance()->manifestDirectory()->absoluteFilePath(m_app->id()),
- ScopedRenamer::NameToNameMinus)) {
- throw Exception(Error::IO, "could not rename %1 to %1-").arg(manifestRename.baseName());
- }
-
- manifestRename.take();
docDirRename.take();
appDirRename.take();
// point of no return
- for (ScopedRenamer *toDelete : { &manifestRename, &docDirRename, &appDirRename }) {
+ for (ScopedRenamer *toDelete : { &docDirRename, &appDirRename }) {
if (toDelete->isRenamed()) {
if (!removeRecursiveHelper(toDelete->baseName() + qL1C('-')))
qCCritical(LogInstaller) << "ERROR: could not remove" << (toDelete->baseName() + qL1C('-'));
}
}
- // we need to call those ApplicationManager methods in the correct thread
+ // we need to call those PackageManager methods in the correct thread
bool finishOk = false;
- QMetaObject::invokeMethod(ApplicationManager::instance(),
- "finishedApplicationInstall",
- Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(bool, finishOk),
- Q_ARG(QString, m_applicationId));
+ QMetaObject::invokeMethod(PackageManager::instance(), [this, &finishOk]()
+ { finishOk = PackageManager::instance()->finishedPackageInstall(m_package->id()); },
+ Qt::BlockingQueuedConnection);
+
if (!finishOk)
- qCWarning(LogInstaller) << "ApplicationManager did not approve deinstallation of " << m_applicationId;
+ qCWarning(LogInstaller) << "PackageManager did not approve deinstallation of " << m_packageId;
} catch (const Exception &e) {
// we need to call those ApplicationManager methods in the correct thread
if (managerApproval) {
bool cancelOk = false;
- QMetaObject::invokeMethod(ApplicationManager::instance(),
- "canceledApplicationInstall",
- Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(bool, cancelOk),
- Q_ARG(QString, m_applicationId));
+ QMetaObject::invokeMethod(PackageManager::instance(), [this, &cancelOk]()
+ { cancelOk = PackageManager::instance()->canceledPackageInstall(m_package->id()); },
+ Qt::BlockingQueuedConnection);
+
if (!cancelOk)
- qCWarning(LogInstaller) << "ApplicationManager could not re-enable app" << m_applicationId << "after a failed removal";
+ qCWarning(LogInstaller) << "PackageManager could not re-enable package" << m_packageId << "after a failed removal";
}
setError(e.errorCode(), e.errorString());
diff --git a/src/installer-lib/deinstallationtask.h b/src/manager-lib/deinstallationtask.h
index f990cee7..a7763d27 100644
--- a/src/installer-lib/deinstallationtask.h
+++ b/src/manager-lib/deinstallationtask.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -42,11 +42,11 @@
#pragma once
-#include <QtAppManInstaller/asynchronoustask.h>
+#include <QtAppManManager/asynchronoustask.h>
QT_BEGIN_NAMESPACE_AM
-class ApplicationInfo;
+class Package;
class InstallationLocation;
class DeinstallationTask : public AsynchronousTask
@@ -54,7 +54,7 @@ class DeinstallationTask : public AsynchronousTask
Q_OBJECT
public:
- DeinstallationTask(ApplicationInfo *app, const InstallationLocation &installationLocation,
+ DeinstallationTask(Package *package, const QString &installationPath, const QString &documentPath,
bool forceDeinstallation, bool keepDocuments, QObject *parent = nullptr);
bool cancel() override;
@@ -63,8 +63,9 @@ protected:
void execute() override;
private:
- ApplicationInfo *m_app;
- const InstallationLocation &m_installationLocation;
+ Package *m_package;
+ QString m_installationPath;
+ QString m_documentPath;
bool m_forceDeinstallation;
bool m_keepDocuments;
bool m_canBeCanceled = true;
diff --git a/src/manager-lib/inprocesssurfaceitem.cpp b/src/manager-lib/inprocesssurfaceitem.cpp
index 9caa228a..7de480ad 100644
--- a/src/manager-lib/inprocesssurfaceitem.cpp
+++ b/src/manager-lib/inprocesssurfaceitem.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/inprocesssurfaceitem.h b/src/manager-lib/inprocesssurfaceitem.h
index a8c80c30..b9faa923 100644
--- a/src/manager-lib/inprocesssurfaceitem.h
+++ b/src/manager-lib/inprocesssurfaceitem.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/installer-lib/installationtask.cpp b/src/manager-lib/installationtask.cpp
index eb6186c7..ef907eb5 100644
--- a/src/installer-lib/installationtask.cpp
+++ b/src/manager-lib/installationtask.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -44,12 +45,11 @@
#include <QMessageAuthenticationCode>
#include "logging.h"
-#include "applicationinstaller_p.h"
-#include "applicationinfo.h"
+#include "packagemanager_p.h"
+#include "packageinfo.h"
#include "packageextractor.h"
-#include "yamlapplicationscanner.h"
#include "exception.h"
-#include "applicationmanager.h"
+#include "packagemanager.h"
#include "sudo.h"
#include "utilities.h"
#include "signature.h"
@@ -62,14 +62,12 @@
Step 1 -- startInstallation()
=============================
- delete <manifestdir>/<id>+
- delete <manifestdir>/<id>-
delete <location>/<id>+
- create dir <manifestdir>/<id>+
create dir <location>/<id>+
set <extractiondir> to <location>/<id>+
+
Step 2 -- unpack files
======================
@@ -81,23 +79,19 @@
if (exists <location>/<id>)
set <isupdate> to <true>
- create installation report at <manifestDir>/installation-report.yaml
+
+ create installation report at <extractiondir>/.installation-report.yaml
if (not <isupdate>)
create document directory
if (optional uid separation)
- chown/chmod recursively in <extractionDir> and document directory
-
- copy info.yaml and the icon file from <extractiondir> to <manifestdir>/<id>+
+ chown/chmod recursively in <extractiondir> and document directory
Step 3.1 -- final rename in finishInstallation()
==================================================
- rename <manifestdir>/<id> to <manifestdir>/<id>-
- rename <manifestdir>/<id>+ to <manifestdir>/<id>
-
if (<isupdate>)
rename <location>/<id> to <location>/<id>-
rename <location>/<id>+ to <location>/<id>
@@ -128,10 +122,12 @@ private:
QMutex InstallationTask::s_serializeFinishInstallation { };
-InstallationTask::InstallationTask(const InstallationLocation &installationLocation, const QUrl &sourceUrl, QObject *parent)
+InstallationTask::InstallationTask(const QString &installationPath, const QString &documentPath,
+ const QUrl &sourceUrl, QObject *parent)
: AsynchronousTask(parent)
- , m_ai(ApplicationInstaller::instance())
- , m_installationLocation(installationLocation)
+ , m_pm(PackageManager::instance())
+ , m_installationPath(installationPath)
+ , m_documentPath(documentPath)
, m_sourceUrl(sourceUrl)
{ }
@@ -167,8 +163,8 @@ void InstallationTask::acknowledge()
void InstallationTask::execute()
{
try {
- if (!m_installationLocation.isValid())
- throw Exception("invalid installation location");
+ if (m_installationPath.isEmpty())
+ throw Exception("no installation location was configured");
TemporaryDir extractionDir;
if (!extractionDir.isValid())
@@ -193,9 +189,9 @@ void InstallationTask::execute()
if (!m_foundInfo || !m_foundIcon)
throw Exception(Error::Package, "package did not contain a valid info.json and icon file");
- QList<QByteArray> chainOfTrust = m_ai->caCertificates();
+ QList<QByteArray> chainOfTrust = m_pm->caCertificates();
- if (ApplicationManager::instance()->securityChecksEnabled()) {
+ if (!m_pm->allowInstallationOfUnsignedPackages()) {
if (!m_extractor->installationReport().storeSignature().isEmpty()) {
// normal package from the store
QByteArray sigDigest = m_extractor->installationReport().digest();
@@ -203,9 +199,9 @@ void InstallationTask::execute()
if (Signature(sigDigest).verify(m_extractor->installationReport().storeSignature(), chainOfTrust)) {
sigOk = true;
- } else if (!m_ai->hardwareId().isEmpty()) {
+ } else if (!m_pm->hardwareId().isEmpty()) {
// did not verify - if we have a hardware-id, try to verify with it
- sigDigest = QMessageAuthenticationCode::hash(sigDigest, m_ai->hardwareId().toUtf8(), QCryptographicHash::Sha256);
+ sigDigest = QMessageAuthenticationCode::hash(sigDigest, m_pm->hardwareId().toUtf8(), QCryptographicHash::Sha256);
if (Signature(sigDigest).verify(m_extractor->installationReport().storeSignature(), chainOfTrust))
sigOk = true;
}
@@ -213,15 +209,14 @@ void InstallationTask::execute()
throw Exception(Error::Package, "could not verify the package's store signature");
} else if (!m_extractor->installationReport().developerSignature().isEmpty()) {
// developer package - needs a device in dev mode
- if (!m_ai->developmentMode())
+ if (!m_pm->developmentMode())
throw Exception(Error::Package, "cannot install development packages on consumer devices");
if (!Signature(m_extractor->installationReport().digest()).verify(m_extractor->installationReport().developerSignature(), chainOfTrust))
throw Exception(Error::Package, "could not verify the package's developer signature");
} else {
- if (!m_ai->allowInstallationOfUnsignedPackages())
- throw Exception(Error::Package, "cannot install unsigned packages");
+ throw Exception(Error::Package, "cannot install unsigned packages");
}
}
@@ -248,14 +243,14 @@ void InstallationTask::execute()
// At this point, the installation is done, so we cannot throw anymore.
- // we need to call those ApplicationManager methods in the correct thread
+ // we need to call those PackageManager methods in the correct thread
bool finishOk = false;
- QMetaObject::invokeMethod(ApplicationManager::instance(),
- "finishedApplicationInstall", Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(bool, finishOk),
- Q_ARG(QString, m_applicationId));
+ QMetaObject::invokeMethod(PackageManager::instance(), [this, &finishOk]()
+ { finishOk = PackageManager::instance()->finishedPackageInstall(m_packageId); },
+ Qt::BlockingQueuedConnection);
+
if (!finishOk)
- qCWarning(LogInstaller) << "ApplicationManager rejected the installation of " << m_applicationId;
+ qCWarning(LogInstaller) << "PackageManager rejected the installation of " << m_packageId;
} catch (const Exception &e) {
setError(e.errorCode(), e.errorString());
@@ -263,13 +258,12 @@ void InstallationTask::execute()
if (m_managerApproval) {
// we need to call those ApplicationManager methods in the correct thread
bool cancelOk = false;
- QMetaObject::invokeMethod(ApplicationManager::instance(),
- "canceledApplicationInstall",
- Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(bool, cancelOk),
- Q_ARG(QString, m_applicationId));
+ QMetaObject::invokeMethod(PackageManager::instance(), [this, &cancelOk]()
+ { cancelOk = PackageManager::instance()->canceledPackageInstall(m_packageId); },
+ Qt::BlockingQueuedConnection);
+
if (!cancelOk)
- qCWarning(LogInstaller) << "ApplicationManager could not remove app" << m_applicationId << "after a failed installation";
+ qCWarning(LogInstaller) << "PackageManager could not remove package" << m_packageId << "after a failed installation";
}
}
@@ -291,25 +285,16 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E
throw Exception(Error::Package, "info.yaml must be the first file in the package. Got %1")
.arg(file);
- YamlApplicationScanner yas;
- m_app.reset(yas.scan(m_extractor->destinationDirectory().absoluteFilePath(file)));
- if (m_app->id() != m_extractor->installationReport().applicationId())
- throw Exception(Error::Package, "the application identifiers in --PACKAGE-HEADER--' and info.yaml do not match");
+ m_package.reset(PackageInfo::fromManifest(m_extractor->destinationDirectory().absoluteFilePath(file)));
+ if (m_package->id() != m_extractor->installationReport().packageId())
+ throw Exception(Error::Package, "the package identifiers in --PACKAGE-HEADER--' and info.yaml do not match");
- m_iconFileName = m_app->icon(); // store it separately as we will give away ApplicationInfo later on
+ m_iconFileName = m_package->icon(); // store it separately as we will give away ApplicationInfo later on
if (m_iconFileName.isEmpty())
throw Exception(Error::Package, "the 'icon' field in info.yaml cannot be empty or absent.");
- InstallationLocation existingLocation = m_ai->installationLocationFromApplication(m_app->id());
-
- if (existingLocation.isValid() && (existingLocation != m_installationLocation)) {
- throw Exception(Error::Package, "the application %1 cannot be installed to %2, since it is already installed to %3")
- .arg(m_app->id(), m_installationLocation.id(), existingLocation.id());
- }
-
- m_app->m_builtIn = false;
- m_applicationId = m_app->id();
+ m_packageId = m_package->id();
m_foundInfo = true;
} else if (m_extractedFileCount == 2) {
@@ -320,7 +305,7 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E
if (file != m_iconFileName)
throw Exception(Error::Package,
- "The application icon (as stated in info.yaml) must be the second file in the package."
+ "The package icon (as stated in info.yaml) must be the second file in the package."
" Expected '%1', got '%2'").arg(m_iconFileName, file);
QFile icon(m_extractor->destinationDirectory().absoluteFilePath(file));
@@ -334,8 +319,26 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E
}
if (m_foundIcon && m_foundInfo) {
- qCDebug(LogInstaller) << "emit taskRequestingInstallationAcknowledge" << id() << "for app" << m_app->id();
- emit m_ai->taskRequestingInstallationAcknowledge(id(), m_app->toVariantMap(),
+ qCDebug(LogInstaller) << "emit taskRequestingInstallationAcknowledge" << id() << "for package" << m_package->id();
+
+ QVariantMap nameMap;
+ auto names = m_package->names();
+ for (auto it = names.constBegin(); it != names.constEnd(); ++it)
+ nameMap.insert(it.key(), it.value());
+
+ QVariantMap applicationData {
+ { qSL("id"), m_package->id() },
+ { qSL("version"), m_package->version() },
+ { qSL("icon"), m_package->icon() },
+ { qSL("displayIcon"), m_package->icon() }, // legacy
+ { qSL("name"), nameMap },
+ { qSL("displayName"), nameMap }, // legacy
+ { qSL("baseDir"), m_package->baseDir().absolutePath() },
+ { qSL("codeDir"), m_package->baseDir().absolutePath() }, // 5.12 backward compatibility
+ { qSL("manifestDir"), m_package->baseDir().absolutePath() }, // 5.12 backward compatibility
+ { qSL("installationLocationId"), qSL("internal-0") } // 5.13 backward compatibility
+ };
+ emit m_pm->taskRequestingInstallationAcknowledge(id(), applicationData,
m_extractor->installationReport().extraMetaData(),
m_extractor->installationReport().extraSignedMetaData());
@@ -352,25 +355,22 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E
QString path = m_extractionDir.absolutePath();
path.chop(1); // remove the '+'
- m_app->setManifestDir(m_manifestDir.absolutePath());
- m_app->setCodeDir(path);
+ m_package->setBaseDir(QDir(path));
}
// we need to find a free uid before we call startingApplicationInstallation
- m_app->m_uid = m_ai->findUnusedUserId();
- m_applicationUid = m_app->m_uid;
+ m_package->m_uid = m_pm->findUnusedUserId();
+ m_applicationUid = m_package->m_uid;
// we need to call those ApplicationManager methods in the correct thread
// this will also exclusively lock the application for us
- // m_app ownership is transferred to the ApplicationManager
- QString appId = m_app->id(); // m_app is gone after the invoke
- QMetaObject::invokeMethod(ApplicationManager::instance(),
- "startingApplicationInstallation",
- Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(bool, m_managerApproval),
- // ugly, but Q_ARG chokes on QT_PREPEND_NAMESPACE_AM...
- QArgument<QT_PREPEND_NAMESPACE_AM(ApplicationInfo *)>(QT_STRINGIFY(QT_PREPEND_NAMESPACE_AM(ApplicationInfo *)), m_app.take()));
+ // m_package ownership is transferred to the ApplicationManager
+ QString packageId = m_package->id(); // m_package is gone after the invoke
+ QMetaObject::invokeMethod(PackageManager::instance(), [this]()
+ { m_managerApproval = PackageManager::instance()->startingPackageInstallation(m_package.take()); },
+ Qt::BlockingQueuedConnection);
+
if (!m_managerApproval)
- throw Exception("Application Manager declined the installation of %1").arg(appId);
+ throw Exception("PackageManager declined the installation of %1").arg(packageId);
// we're not interested in any other files from here on...
m_extractor->setFileExtractedCallback(nullptr);
@@ -379,36 +379,27 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E
void InstallationTask::startInstallation() Q_DECL_NOEXCEPT_EXPR(false)
{
- // 1. delete $manifestDir+ and $manifestDir-
- m_manifestDir.setPath(m_ai->manifestDirectory()->absoluteFilePath(m_applicationId));
- removeRecursiveHelper(m_manifestDir.absolutePath() + qL1C('+'));
- removeRecursiveHelper(m_manifestDir.absolutePath() + qL1C('-'));
-
// 2. delete old, partial installation
- QDir installationDir = QString(m_installationLocation.installationPath() + qL1C('/'));
- QString installationTarget = m_applicationId + qL1C('+');
+ QDir installationDir = QString(m_installationPath + qL1C('/'));
+ QString installationTarget = m_packageId + qL1C('+');
if (installationDir.exists(installationTarget)) {
if (!removeRecursiveHelper(installationDir.absoluteFilePath(installationTarget)))
throw Exception("could not remove old, partial installation %1/%2").arg(installationDir).arg(installationTarget);
}
- // 3. create $manifestDir+
- if (!m_manifestDirPlusCreator.create(m_manifestDir.absolutePath() + qL1C('+')))
- throw Exception("could not create manifest sub-directory %1+").arg(m_manifestDir);
-
// 4. create new installation
if (!m_installationDirCreator.create(installationDir.absoluteFilePath(installationTarget)))
throw Exception("could not create installation directory %1/%2").arg(installationDir).arg(installationTarget);
m_extractionDir = installationDir;
if (!m_extractionDir.cd(installationTarget))
throw Exception("could not cd into installation directory %1/%2").arg(installationDir).arg(installationTarget);
- m_applicationDir.setPath(installationDir.absoluteFilePath(m_applicationId));
+ m_applicationDir.setPath(installationDir.absoluteFilePath(m_packageId));
}
void InstallationTask::finishInstallation() Q_DECL_NOEXCEPT_EXPR(false)
{
- QDir documentDirectory(m_installationLocation.documentPath());
+ QDir documentDirectory(m_documentPath);
ScopedDirectoryCreator documentDirCreator;
enum { Installation, Update } mode = Installation;
@@ -418,9 +409,8 @@ void InstallationTask::finishInstallation() Q_DECL_NOEXCEPT_EXPR(false)
// create the installation report
InstallationReport report = m_extractor->installationReport();
- report.setInstallationLocationId(m_installationLocation.id());
- QFile reportFile(m_manifestDirPlusCreator.dir().absoluteFilePath(qSL("installation-report.yaml")));
+ QFile reportFile(m_extractionDir.absoluteFilePath(qSL(".installation-report.yaml")));
if (!reportFile.open(QFile::WriteOnly) || !report.serialize(&reportFile))
throw Exception(reportFile, "could not write the installation report");
reportFile.close();
@@ -428,22 +418,22 @@ void InstallationTask::finishInstallation() Q_DECL_NOEXCEPT_EXPR(false)
// create the document directories when installing (not needed on updates)
if (mode == Installation) {
// this package may have been installed earlier and the document directory may not have been removed
- if (!documentDirectory.cd(m_applicationId)) {
- if (!documentDirCreator.create(documentDirectory.absoluteFilePath(m_applicationId)))
- throw Exception(Error::IO, "could not create the document directory %1").arg(documentDirectory.filePath(m_applicationId));
+ if (!documentDirectory.cd(m_packageId)) {
+ if (!documentDirCreator.create(documentDirectory.absoluteFilePath(m_packageId)))
+ throw Exception(Error::IO, "could not create the document directory %1").arg(documentDirectory.filePath(m_packageId));
}
}
#ifdef Q_OS_UNIX
// update the owner, group and permission bits on both the installation and document directories
SudoClient *root = SudoClient::instance();
- if (m_ai->isApplicationUserIdSeparationEnabled() && root) {
+ if (m_pm->isApplicationUserIdSeparationEnabled() && root) {
uid_t uid = m_applicationUid;
- gid_t gid = m_ai->commonApplicationGroupId();
+ gid_t gid = m_pm->commonApplicationGroupId();
- if (!root->setOwnerAndPermissionsRecursive(documentDirectory.filePath(m_applicationId), uid, gid, 02700)) {
+ if (!root->setOwnerAndPermissionsRecursive(documentDirectory.filePath(m_packageId), uid, gid, 02700)) {
throw Exception(Error::IO, "could not recursively change the owner to %1:%2 and the permission bits to %3 in %4")
- .arg(uid).arg(gid).arg(02700, 0, 8).arg(documentDirectory.filePath(m_applicationId));
+ .arg(uid).arg(gid).arg(02700, 0, 8).arg(documentDirectory.filePath(m_packageId));
}
if (!root->setOwnerAndPermissionsRecursive(m_extractionDir.path(), uid, gid, 0440)) {
@@ -453,26 +443,14 @@ void InstallationTask::finishInstallation() Q_DECL_NOEXCEPT_EXPR(false)
}
#endif
- // copy meta-data to manifest directory
- for (const QString &file : { qSL("info.yaml"), m_iconFileName })
- if (!QFile::copy(m_extractionDir.absoluteFilePath(file), m_manifestDirPlusCreator.dir().absoluteFilePath(file))) {
- throw Exception(Error::IO, "could not copy %1 from the application directory to the manifest directory").arg(file);
- }
- // in case we need persistent data in addition to info.yaml and the icon file,
- // we could copy these out of the image right now...
-
// final rename
// POSIX cannot atomically rename directories, if the destination directory exists
// and is non-empty. We need to do a double-rename in this case, which might fail!
// The image is a file, so this limitation does not apply!
- ScopedRenamer renameManifest;
ScopedRenamer renameApplication;
- if (!renameManifest.rename(m_manifestDir, (mode == Update ? ScopedRenamer::NameToNameMinus | ScopedRenamer::NamePlusToName : ScopedRenamer::NamePlusToName)))
- throw Exception(Error::IO, "could not rename manifest directory %1+ to %1 (including a backup to %1-)").arg(m_manifestDir);
-
if (mode == Update) {
if (!renameApplication.rename(m_applicationDir, ScopedRenamer::NamePlusToName | ScopedRenamer::NameToNameMinus))
throw Exception(Error::IO, "could not rename application directory %1+ to %1 (including a backup to %1-)").arg(m_applicationDir);
@@ -486,11 +464,9 @@ void InstallationTask::finishInstallation() Q_DECL_NOEXCEPT_EXPR(false)
setState(CleaningUp);
renameApplication.take();
- renameManifest.take();
documentDirCreator.take();
m_installationDirCreator.take();
- m_manifestDirPlusCreator.take();
// this should not be necessary, but it also won't hurt
if (mode == Update)
diff --git a/src/installer-lib/installationtask.h b/src/manager-lib/installationtask.h
index 5f5881b3..7d3163d2 100644
--- a/src/installer-lib/installationtask.h
+++ b/src/manager-lib/installationtask.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -47,14 +47,14 @@
#include <QWaitCondition>
#include <QMutex>
-#include <QtAppManInstaller/applicationinstaller.h>
#include <QtAppManApplication/installationreport.h>
-#include <QtAppManInstaller/asynchronoustask.h>
-#include <QtAppManInstaller/scopeutilities.h>
+#include <QtAppManManager/asynchronoustask.h>
+#include <QtAppManManager/scopeutilities.h>
QT_BEGIN_NAMESPACE_AM
-class ApplicationInfo;
+class PackageInfo;
+class PackageManager;
class PackageExtractor;
@@ -62,8 +62,8 @@ class InstallationTask : public AsynchronousTask
{
Q_OBJECT
public:
- InstallationTask(const InstallationLocation &installationLocation, const QUrl &sourceUrl,
- QObject *parent = nullptr);
+ InstallationTask(const QString &installationPath, const QString &documentPath,
+ const QUrl &sourceUrl, QObject *parent = nullptr);
~InstallationTask() override;
void acknowledge();
@@ -81,8 +81,9 @@ private:
void checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_EXPR(false);
private:
- ApplicationInstaller *m_ai;
- const InstallationLocation &m_installationLocation;
+ PackageManager *m_pm;
+ QString m_installationPath;
+ QString m_documentPath;
QUrl m_sourceUrl;
bool m_foundInfo = false;
bool m_foundIcon = false;
@@ -90,7 +91,7 @@ private:
bool m_locked = false;
uint m_extractedFileCount = 0;
bool m_managerApproval = false;
- QScopedPointer<ApplicationInfo> m_app;
+ QScopedPointer<PackageInfo> m_package;
uint m_applicationUid = uint(-1);
// changes to these 4 member variables are protected by m_mutex
@@ -101,11 +102,9 @@ private:
static QMutex s_serializeFinishInstallation;
- QDir m_manifestDir;
QDir m_applicationDir;
QDir m_extractionDir;
- ScopedDirectoryCreator m_manifestDirPlusCreator;
ScopedDirectoryCreator m_installationDirCreator;
};
diff --git a/src/manager-lib/intentaminterface.cpp b/src/manager-lib/intentaminterface.cpp
index 713b2039..52b8e5be 100644
--- a/src/manager-lib/intentaminterface.cpp
+++ b/src/manager-lib/intentaminterface.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -68,6 +69,9 @@
#include "qmlinprocessruntime.h"
#include "application.h"
#include "applicationmanager.h"
+#include "package.h"
+#include "packagemanager.h"
+#include "applicationinfo.h"
QT_BEGIN_NAMESPACE_AM
@@ -78,112 +82,81 @@ static QString sysUiId = qSL(":sysui:");
// vvv IntentAMImplementation vvv
-IntentServer *IntentAMImplementation::createIntentServerAndClientInstance(const QMap<QString, int> &timeouts)
+IntentServer *IntentAMImplementation::createIntentServerAndClientInstance(PackageManager *packageManager,
+ int disambiguationTimeout,
+ int startApplicationTimeout,
+ int replyFromApplicationTimeout,
+ int replyFromSystemTimeout)
{
auto intentServerAMInterface = new IntentServerAMImplementation;
auto intentClientAMInterface = new IntentClientAMImplementation(intentServerAMInterface);
auto intentServer = IntentServer::createInstance(intentServerAMInterface);
auto intentClient = IntentClient::createInstance(intentClientAMInterface);
- auto it = timeouts.constFind(qSL("disambiguation"));
- if (it != timeouts.cend())
- intentServer->setDisambiguationTimeout(it.value());
- it = timeouts.constFind(qSL("startApplication"));
- if (it != timeouts.cend())
- intentServer->setStartApplicationTimeout(it.value());
- it = timeouts.constFind(qSL("replyFromApplication"));
- if (it != timeouts.cend()) {
- int t = it.value();
-
- // These timeouts are for the same thing - the time needed for the application's handler to
- // generate a reply - but one is for the server side, while the other for the client side.
- // Having two separate config values would be confusing, so we set the application side to
- // 90% of the server side, because the communication overhead is not included there.
+ intentServer->setDisambiguationTimeout(disambiguationTimeout);
+ intentServer->setStartApplicationTimeout(startApplicationTimeout);
+
+ // These timeouts are for the same thing - the time needed for the application's handler to
+ // generate a reply - but one is for the server side, while the other for the client side.
+ // Having two separate config values would be confusing, so we set the application side to
+ // 90% of the server side, because the communication overhead is not included there.
+ {
+ int t = replyFromApplicationTimeout;
intentServer->setReplyFromApplicationTimeout(t);
intentClient->setReplyFromApplicationTimeout(t <= 0 ? t : int(t * 0.9));
}
- it = timeouts.constFind(qSL("requestToSystem"));
- if (it != timeouts.cend())
- intentClient->setReplyFromSystemTimeout(it.value());
-
-
+ intentClient->setReplyFromSystemTimeout(replyFromSystemTimeout);
// this way, deleting the server (the return value of this factory function) will get rid
// of both client and server as well as both their AM interfaces
intentClient->setParent(intentServer);
- return intentServer;
-}
-void IntentAMImplementation::addApplicationIntents(AbstractApplication *app, IntentServer *intentServer)
-{
- if (app->isAlias())
- return;
-
- QSet<QString> intentIds;
- const auto intents = app->nonAliasedInfo()->intents();
-
- if (!intents.isEmpty())
- intentServer->addApplication(app->id());
-
- for (const auto &intent : intents) {
- /* example:
- id: io.qt.shareImage
- handledBy: main
- visibility: public*|private
- requiredCapabilities: [ a, b ]
- parameterMatch:
- mimeType: "^image/.*\.png$"
- */
- const QVariantMap map = intent.toMap();
- const QString id = map[qSL("id")].toString();
- Intent::Visibility visibility = Intent::Public;
- const QString visibilityStr = map[qSL("visibility")].toString();
- QString handledBy = map[qSL("handledBy")].toString();
- const QStringList capabilities = map[qSL("requiredCapabilities")].toStringList();
- const QVariantMap parameterMatch = map[qSL("parameterMatch")].toMap(); // do we really need that?
-
- if (id.isEmpty())
- throw Exception(Error::Intents, "intents need to have an id (app %1)").arg(app->id());
- if (intentIds.contains(id))
- throw Exception(Error::Intents, "found two intent handlers for %2 (app %1)").arg(app->id()).arg(id);
- intentIds << id;
-
- if (visibilityStr == qL1S("private"))
- visibility = Intent::Private;
- else if (!visibilityStr.isEmpty() && (visibilityStr != qL1S("public"))) {
- throw Exception(Error::Intents, "intent visibilty %3 is invalid (intent %2, app %1)")
- .arg(app->id()).arg(id).arg(visibilityStr);
- }
-
- if (handledBy == qL1S("main"))
- handledBy.clear();
- // we do not support bg services yet
- if (!handledBy.isEmpty()) {
- throw Exception(Error::Intents, "service background handlers for intent are not supported yet (intent %2, app %1)")
- .arg(app->id()).arg(id).arg(visibilityStr);
- }
-
- qCDebug(LogSystem).nospace().noquote() << " * " << id << " [app: " << app->id() << "]";
+ // connect the APIs of the PackageManager and the IntentServer
+ // the Intent API does not use AM internal types, so we have to translate using id strings:
+ // the idea behind this is that the Intent subsystem could be useful outside of the AM as well,
+ // so we try not to use AM specific classes in the intent-server and intent-client modules.
+ QObject::connect(packageManager, &PackageManager::packageAdded,
+ intentServer, &IntentServer::addPackage);
+ QObject::connect(packageManager, &PackageManager::packageAboutToBeRemoved,
+ intentServer, &IntentServer::removePackage);
+
+ QObject::connect(&packageManager->internalSignals, &PackageManagerInternalSignals::registerApplication,
+ intentServer, [intentServer](ApplicationInfo *applicationInfo, Package *package) {
+ intentServer->addApplication(applicationInfo->id(), package->id());
+ });
+ QObject::connect(&packageManager->internalSignals, &PackageManagerInternalSignals::unregisterApplication,
+ intentServer, [intentServer](ApplicationInfo *applicationInfo, Package *package) {
+ intentServer->removeApplication(applicationInfo->id(), package->id());
+ });
- if (!intentServer->addIntent(id, app->id(), handledBy, capabilities,
- visibility, parameterMatch)) {
- throw Exception(Error::Intents, "could not add intent %2 for app %1").arg(app->id()).arg(id);
+ QObject::connect(&packageManager->internalSignals, &PackageManagerInternalSignals::registerIntent,
+ intentServer, [intentServer](IntentInfo *intentInfo, Package *package) {
+
+ if (!intentServer->addIntent(intentInfo->id(), package->id(), intentInfo->handlingApplicationId(),
+ intentInfo->requiredCapabilities(),
+ intentInfo->visibility() == IntentInfo::Public ? Intent::Public
+ : Intent::Private,
+ intentInfo->parameterMatch(), intentInfo->names(),
+ QUrl::fromLocalFile(package->info()->baseDir().absoluteFilePath(intentInfo->icon())),
+ intentInfo->categories())) {
+ throw Exception(Error::Intents, "could not add intent %1 for package %2")
+ .arg(intentInfo->id()).arg(package->id());
}
- }
-}
-
-void IntentAMImplementation::removeApplicationIntents(AbstractApplication *app, IntentServer *intentServer)
-{
- if (app->isAlias())
- return;
- auto intents = intentServer->filterByHandlingApplicationId(intentServer->all(), app->id());
- for (const auto &intent : intents)
+ qCDebug(LogSystem).nospace().noquote() << " ++ intent: " << intentInfo->id() << " [package: " << package->id() << "]";
+ });
+ QObject::connect(&packageManager->internalSignals, &PackageManagerInternalSignals::unregisterIntent,
+ intentServer, [intentServer](IntentInfo *intentInfo, Package *package) {
+ Intent *intent = intentServer->packageIntent(intentInfo->id(), package->id(),
+ intentInfo->parameterMatch());
+ qCDebug(LogSystem).nospace().noquote() << " -- intent: " << intentInfo->id() << " [package: " << package->id() << "]";
+ Q_ASSERT(intent);
intentServer->removeIntent(intent);
-
- intentServer->removeApplication(app->id());
+ });
+ return intentServer;
}
+
// ^^^ IntentAMImplementation ^^^
//////////////////////////////////////////////////////////////////////////
// vvv IntentServerAMImplementation vvv
@@ -433,6 +406,7 @@ IntentServerInProcessIpcConnection *IntentServerInProcessIpcConnection::createSy
{
auto ipcConnection = create(nullptr, iface);
ipcConnection->m_isSystemUi = true;
+ ipcConnection->setParent(iface);
return ipcConnection;
}
@@ -542,6 +516,7 @@ void IntentServerDBusIpcConnection::replyFromApplication(const QString &requestI
convertFromDBusVariant(result).toMap());
}
+
#endif // defined(AM_MULTI_PROCESS)
QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/intentaminterface.h b/src/manager-lib/intentaminterface.h
index c2db4a44..49136b13 100644
--- a/src/manager-lib/intentaminterface.h
+++ b/src/manager-lib/intentaminterface.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -54,19 +55,20 @@
#include <QtAppManCommon/global.h>
#include <QtAppManIntentServer/intentserversysteminterface.h>
#include <QtAppManIntentClient/intentclientsysteminterface.h>
+#include <QtAppManApplication/intentinfo.h>
class IntentInterfaceAdaptor;
QT_BEGIN_NAMESPACE_AM
class Application;
-class AbstractApplication;
+class PackageManager;
class IntentServerRequest;
namespace IntentAMImplementation {
-IntentServer *createIntentServerAndClientInstance(const QMap<QString, int> &timeouts);
-void addApplicationIntents(AbstractApplication *app, IntentServer *intentServer);
-void removeApplicationIntents(AbstractApplication *app, IntentServer *intentServer);
+IntentServer *createIntentServerAndClientInstance(PackageManager *packageManager, int disambiguationTimeout,
+ int startApplicationTimeout, int replyFromApplicationTimeout,
+ int replyFromSystemTimeout);
}
// the server side
diff --git a/src/manager-lib/manager-lib.pro b/src/manager-lib/manager-lib.pro
index 170792bd..71fad983 100644
--- a/src/manager-lib/manager-lib.pro
+++ b/src/manager-lib/manager-lib.pro
@@ -41,7 +41,6 @@ HEADERS += \
application.h \
applicationmanager.h \
applicationmodel.h \
- applicationdatabase.h \
notificationmanager.h \
abstractcontainer.h \
containerfactory.h \
@@ -57,6 +56,9 @@ HEADERS += \
amnamespace.h \
intentaminterface.h \
processstatus.h \
+ package.h \
+ packagemanager.h \
+ packagemanager_p.h \
!headless:HEADERS += \
qmlinprocessapplicationmanagerwindow.h \
@@ -70,7 +72,6 @@ SOURCES += \
application.cpp \
applicationmanager.cpp \
applicationmodel.cpp \
- applicationdatabase.cpp \
notificationmanager.cpp \
abstractcontainer.cpp \
containerfactory.cpp \
@@ -83,6 +84,8 @@ SOURCES += \
debugwrapper.cpp \
intentaminterface.cpp \
processstatus.cpp \
+ packagemanager.cpp \
+ package.cpp \
!headless:SOURCES += \
qmlinprocessapplicationmanagerwindow.cpp \
@@ -96,4 +99,26 @@ qtHaveModule(qml):SOURCES += \
# compile the moc-data into the exporting binary (appman itself)
HEADERS += ../plugin-interfaces/containerinterface.h
+
+!disable-installer {
+
+ QT_FOR_PRIVATE *= \
+ appman_package-private \
+ appman_crypto-private \
+
+ HEADERS += \
+ asynchronoustask.h \
+ deinstallationtask.h \
+ installationtask.h \
+ scopeutilities.h \
+ sudo.h \
+
+ SOURCES += \
+ asynchronoustask.cpp \
+ installationtask.cpp \
+ deinstallationtask.cpp \
+ scopeutilities.cpp \
+ sudo.cpp \
+}
+
load(qt_module)
diff --git a/src/manager-lib/nativeruntime.cpp b/src/manager-lib/nativeruntime.cpp
index 408efa3e..5313a3b3 100644
--- a/src/manager-lib/nativeruntime.cpp
+++ b/src/manager-lib/nativeruntime.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -75,6 +75,7 @@ QT_BEGIN_NAMESPACE_AM
QT_END_NAMESPACE_AM
# include <dlfcn.h>
# include <sys/socket.h>
+# include <signal.h>
QT_BEGIN_NAMESPACE_AM
static qint64 getDBusPeerPid(const QDBusConnection &conn)
@@ -216,7 +217,7 @@ bool NativeRuntime::initialize()
if (!m_app)
return false;
- m_container->setProgram(m_app->nonAliasedInfo()->absoluteCodeFilePath());
+ m_container->setProgram(m_app->info()->absoluteCodeFilePath());
m_container->setBaseDirectory(m_app->codeDir());
return true;
}
@@ -224,12 +225,16 @@ bool NativeRuntime::initialize()
void NativeRuntime::shutdown(int exitCode, Am::ExitStatus status)
{
- if (!m_isQuickLauncher || m_connectedToRuntimeInterface) {
+ // see NativeRuntime::stop() below
+ if ((status == Am::CrashExit) && (exitCode == SIGTERM || exitCode == SIGKILL))
+ status = Am::ForcedExit;
+
+ if (!m_isQuickLauncher || m_connectedToApplicationInterface) {
qCDebug(LogSystem) << "NativeRuntime (id:" << (m_app ? m_app->id() : qSL("(none)"))
<< "pid:" << m_process->processId() << ") exited with code:" << exitCode
<< "status:" << status;
}
- m_connectedToRuntimeInterface = m_dbusConnection = false;
+ m_connectedToApplicationInterface = m_dbusConnection = false;
QDBusConnection connection(m_dbusConnectionName);
emit applicationDisconnectedFromPeerDBus(connection, application());
@@ -272,7 +277,7 @@ bool NativeRuntime::start()
QVariantMap openGLConfig;
if (m_app)
- openGLConfig = m_app->nonAliasedInfo()->openGLConfiguration();
+ openGLConfig = m_app->info()->openGLConfiguration();
if (openGLConfig.isEmpty())
openGLConfig = manager()->systemOpenGLConfiguration();
if (!openGLConfig.isEmpty())
@@ -303,12 +308,7 @@ bool NativeRuntime::start()
{ qSL("QT_IM_MODULE"), QString() }, // Applications should use wayland text input
{ qSL("QT_SCALE_FACTOR"), QString() }, // do not scale wayland clients
{ qSL("AM_CONFIG"), QString::fromUtf8(QtYaml::yamlFromVariantDocuments({ config })) },
-
-#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
{ qSL("QT_WAYLAND_SHELL_INTEGRATION"), qSL("xdg-shell")},
-#else
- { qSL("QT_WAYLAND_SHELL_INTEGRATION"), qSL("xdg-shell-v5")},
-#endif
};
if (!Logging::isDltEnabled()) {
@@ -346,6 +346,9 @@ bool NativeRuntime::start()
if (!m_document.isNull())
args << qSL("--start-argument") << m_document;
+
+ if (!Logging::isDltEnabled())
+ args << qSL("--no-dlt-logging");
}
if (m_isQuickLauncher)
@@ -375,8 +378,8 @@ void NativeRuntime::stop(bool forceKill)
setState(Am::ShuttingDown);
emit aboutToStop();
- if (!m_connectedToRuntimeInterface) {
- //The launcher didn't connected to the RuntimeInterface yet, so it won't get the quit signal
+ if (!m_connectedToApplicationInterface) {
+ //The launcher didn't connected to the ApplicationInterface yet, so it won't get the quit signal
m_process->terminate();
} else if (forceKill) {
m_process->kill();
@@ -393,8 +396,10 @@ void NativeRuntime::stop(bool forceKill)
void NativeRuntime::onProcessStarted()
{
- if (!m_startedViaLauncher && !application()->nonAliasedInfo()->supportsApplicationInterface())
+ if (!m_startedViaLauncher
+ && !(application()->info()->supportsApplicationInterface() || manager()->supportsQuickLaunch())) {
setState(Am::Running);
+ }
}
void NativeRuntime::onProcessError(Am::ProcessError error)
@@ -449,7 +454,7 @@ void NativeRuntime::onDBusPeerConnection(const QDBusConnection &connection)
void NativeRuntime::onApplicationFinishedInitialization()
{
- m_connectedToRuntimeInterface = true;
+ m_connectedToApplicationInterface = true;
if (m_app) {
// now we know which app was launched, so initialize any additional interfaces on the p2p bus
@@ -468,7 +473,7 @@ bool NativeRuntime::startApplicationViaLauncher()
return false;
QString baseDir = m_container->mapHostPathToContainer(m_app->codeDir());
- QString pathInContainer = m_container->mapHostPathToContainer(m_app->nonAliasedInfo()->absoluteCodeFilePath());
+ QString pathInContainer = m_container->mapHostPathToContainer(m_app->info()->absoluteCodeFilePath());
emit m_runtimeInterface->startApplication(baseDir, pathInContainer, m_document, m_mimeType,
convertFromJSVariant(QVariant(m_app->info()->toVariantMap())).toMap(),
diff --git a/src/manager-lib/nativeruntime.h b/src/manager-lib/nativeruntime.h
index 931d8e8b..1343402c 100644
--- a/src/manager-lib/nativeruntime.h
+++ b/src/manager-lib/nativeruntime.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -124,7 +124,7 @@ private:
QString m_document;
QString m_mimeType;
- bool m_connectedToRuntimeInterface = false;
+ bool m_connectedToApplicationInterface = false;
bool m_dbusConnection = false;
QString m_dbusConnectionName;
diff --git a/src/manager-lib/nativeruntime_p.h b/src/manager-lib/nativeruntime_p.h
index 82fff7bf..2c0e514d 100644
--- a/src/manager-lib/nativeruntime_p.h
+++ b/src/manager-lib/nativeruntime_p.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/notificationmanager.cpp b/src/manager-lib/notificationmanager.cpp
index 26c804fc..04fe150e 100644
--- a/src/manager-lib/notificationmanager.cpp
+++ b/src/manager-lib/notificationmanager.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -52,6 +52,7 @@
#include "notificationmanager.h"
#include "qml-utilities.h"
#include "dbus-utilities.h"
+#include "package.h"
/*!
\externalpage https://developer.gnome.org/notification-spec/
@@ -207,7 +208,7 @@ enum Roles
struct NotificationData
{
uint id;
- AbstractApplication *application;
+ Application *application;
uint priority;
QString summary;
QString body;
@@ -353,7 +354,8 @@ QVariant NotificationManager::data(const QModelIndex &index, int role) const
case Icon:
if (!n->iconUrl.isEmpty())
return n->iconUrl;
- return n->application ? n->application->icon() : QString();
+ return n->application && n->application->package() ? n->application->package()->icon()
+ : QString();
case Image:
return n->imageUrl;
case ShowActionsAsIcons:
@@ -580,7 +582,7 @@ uint NotificationManager::notifyHelper(const QString &app_name, uint id, bool re
qCDebug(LogNotifications) << " -> adding new notification with id" << id;
}
- AbstractApplication *app = ApplicationManager::instance()->fromId(app_name);
+ Application *app = ApplicationManager::instance()->fromId(app_name);
if (replaces && app != n->application) {
// no hijacking allowed
diff --git a/src/manager-lib/notificationmanager.h b/src/manager-lib/notificationmanager.h
index b97d4fa5..8a25a81b 100644
--- a/src/manager-lib/notificationmanager.h
+++ b/src/manager-lib/notificationmanager.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/package.cpp b/src/manager-lib/package.cpp
new file mode 100644
index 00000000..e180fc7b
--- /dev/null
+++ b/src/manager-lib/package.cpp
@@ -0,0 +1,247 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QLocale>
+
+#include "package.h"
+#include "packageinfo.h"
+#include "applicationinfo.h"
+
+QT_BEGIN_NAMESPACE_AM
+
+Package::Package(PackageInfo *packageInfo, State initialState)
+ : m_info(packageInfo)
+ , m_state(initialState)
+{ }
+
+QString Package::id() const
+{
+ return info()->id();
+}
+
+bool Package::isBuiltIn() const
+{
+ return m_info->isBuiltIn();
+}
+
+bool Package::builtInHasRemovableUpdate() const
+{
+ return isBuiltIn() && m_updatedInfo;
+}
+
+QString Package::version() const
+{
+ return info()->version();
+}
+
+QString Package::name() const
+{
+ QString name;
+ if (!info()->names().isEmpty()) {
+ name = info()->name(QLocale::system().name()); //TODO: language changes
+ if (name.isEmpty())
+ name = info()->name(qSL("en"));
+ if (name.isEmpty())
+ name = info()->name(qSL("en_US"));
+ if (name.isEmpty())
+ name = *info()->names().constBegin();
+ } else {
+ name = id();
+ }
+ return name;
+}
+
+QVariantMap Package::names() const
+{
+ QVariantMap names;
+ for (auto it = info()->names().cbegin(); it != info()->names().cend(); ++it)
+ names.insert(it.key(), it.value());
+ return names;
+}
+
+QString Package::description() const
+{
+ QString description;
+ if (!info()->descriptions().isEmpty()) {
+ description = info()->description(QLocale::system().name()); //TODO: language changes
+ if (description.isEmpty())
+ description = info()->description(qSL("en"));
+ if (description.isEmpty())
+ description = info()->description(qSL("en_US"));
+ if (description.isEmpty())
+ description = *info()->descriptions().constBegin();
+ }
+ return description;
+}
+
+QVariantMap Package::descriptions() const
+{
+ QVariantMap descriptions;
+ for (auto it = info()->descriptions().cbegin(); it != info()->descriptions().cend(); ++it)
+ descriptions.insert(it.key(), it.value());
+ return descriptions;
+}
+
+QStringList Package::categories() const
+{
+ return info()->categories();
+}
+
+QUrl Package::icon() const
+{
+ if (info()->icon().isEmpty())
+ return QUrl();
+
+ QDir dir;
+ switch (state()) {
+ default:
+ case Installed:
+ dir = info()->baseDir();
+ break;
+ case BeingInstalled:
+ case BeingUpdated:
+ dir = QDir(info()->baseDir().absolutePath() + QLatin1Char('+'));
+ break;
+ case BeingRemoved:
+ dir = QDir(info()->baseDir().absolutePath() + QLatin1Char('-'));
+ break;
+ }
+ return QUrl::fromLocalFile(dir.absoluteFilePath(info()->icon()));
+}
+
+void Package::setState(State state)
+{
+ if (m_state != state) {
+ m_state = state;
+ emit stateChanged(m_state);
+ }
+}
+
+void Package::setProgress(qreal progress)
+{
+ m_progress = progress;
+}
+
+PackageInfo *Package::info() const
+{
+ return m_updatedInfo ? m_updatedInfo : m_info;
+}
+
+PackageInfo *Package::baseInfo() const
+{
+ return m_info;
+}
+
+PackageInfo *Package::updatedInfo() const
+{
+ return m_updatedInfo;
+}
+
+PackageInfo *Package::setUpdatedInfo(PackageInfo *info)
+{
+ Q_ASSERT(!info || (m_info && info->id() == m_info->id()));
+ Q_ASSERT(info != m_updatedInfo);
+
+ auto old = m_updatedInfo;
+ m_updatedInfo = info;
+ emit bulkChange();
+ return old;
+}
+
+PackageInfo *Package::setBaseInfo(PackageInfo *info)
+{
+ Q_ASSERT(info != m_info);
+
+ auto old = m_info;
+ m_info = info;
+ emit bulkChange();
+ return old;
+}
+
+bool Package::isBlocked() const
+{
+ return m_blocked > 0;
+}
+
+bool Package::block()
+{
+ bool blockedNow = (m_blocked.fetchAndAddOrdered(1) == 0);
+ if (blockedNow) {
+ m_blockedApps = info()->applications();
+ m_blockedAppsCount = m_blockedApps.count();
+ emit blockedChanged(true);
+ }
+ return blockedNow;
+}
+
+bool Package::unblock()
+{
+ bool unblockedNow = (m_blocked.fetchAndSubOrdered(1) == 1);
+ if (unblockedNow) {
+ m_blockedApps.clear();
+ m_blockedAppsCount = 0;
+ emit blockedChanged(false);
+ }
+ return unblockedNow;
+
+}
+
+void Package::applicationStoppedDueToBlock(const QString &appId)
+{
+ if (!isBlocked())
+ return;
+
+ auto it = std::find_if(m_blockedApps.cbegin(), m_blockedApps.cend(), [appId](const ApplicationInfo *appInfo) {
+ return appInfo->id() == appId;
+ });
+ if (it != m_blockedApps.cend())
+ m_blockedApps.removeOne(*it);
+ m_blockedAppsCount = m_blockedApps.count();
+}
+
+bool Package::areAllApplicationsStoppedDueToBlock() const
+{
+ return isBlocked() && !m_blockedAppsCount;
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/package.h b/src/manager-lib/package.h
new file mode 100644
index 00000000..d8513bb1
--- /dev/null
+++ b/src/manager-lib/package.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtAppManCommon/global.h>
+#include <QtAppManApplication/packageinfo.h>
+#include <QUrl>
+#include <QString>
+#include <QAtomicInt>
+#include <QObject>
+
+QT_BEGIN_NAMESPACE_AM
+
+
+class Package : public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/PackageObject 2.0 UNCREATABLE")
+ Q_PROPERTY(QString id READ id CONSTANT)
+ Q_PROPERTY(bool builtIn READ isBuiltIn NOTIFY bulkChange)
+ Q_PROPERTY(bool builtInHasRemovableUpdate READ builtInHasRemovableUpdate NOTIFY bulkChange)
+ Q_PROPERTY(QUrl icon READ icon NOTIFY bulkChange)
+ Q_PROPERTY(QString version READ version NOTIFY bulkChange)
+ Q_PROPERTY(QString name READ name NOTIFY bulkChange)
+ Q_PROPERTY(QVariantMap names READ names NOTIFY bulkChange)
+ Q_PROPERTY(QString description READ description NOTIFY bulkChange)
+ Q_PROPERTY(QVariantMap descriptions READ descriptions NOTIFY bulkChange)
+ Q_PROPERTY(QStringList categories READ categories NOTIFY bulkChange)
+ Q_PROPERTY(State state READ state NOTIFY stateChanged)
+ Q_PROPERTY(bool blocked READ isBlocked NOTIFY blockedChanged)
+
+public:
+ enum State {
+ Installed,
+ BeingInstalled,
+ BeingUpdated,
+ BeingDowngraded,
+ BeingRemoved
+ };
+ Q_ENUM(State)
+
+ Package(PackageInfo *packageInfo, State initialState = Installed);
+
+ QString id() const;
+ bool isBuiltIn() const;
+ bool builtInHasRemovableUpdate() const;
+ QUrl icon() const;
+ QString version() const;
+ QString name() const;
+ QVariantMap names() const;
+ QString description() const;
+ QVariantMap descriptions() const;
+ QStringList categories() const;
+
+ State state() const { return m_state; }
+ qreal progress() const { return m_progress; }
+
+ void setState(State state);
+ void setProgress(qreal progress);
+
+ /*
+ All packages have a base info.
+
+ Built-in packages, when updated, also get an updated info.
+ The updated info then overlays the base one. Subsequent updates
+ just replace the updated info. When requested to be removed, a
+ built-in packages only loses its updated info, returning to
+ expose the base one.
+
+ Regular packages (ie, non-built-in) only have a base info. When
+ updated, their base info gets replaced and thus there's no way to go
+ back to a previous version. Regular packages get completely
+ removed when requested.
+ */
+
+ // Returns the updated info, if there's one. Otherwise returns the base info.
+ PackageInfo *info() const;
+ PackageInfo *baseInfo() const;
+ PackageInfo *updatedInfo() const;
+ PackageInfo *setUpdatedInfo(PackageInfo *info);
+ PackageInfo *setBaseInfo(PackageInfo *info);
+
+ bool isBlocked() const;
+ bool block();
+ bool unblock();
+
+ // function for Application to report it has stopped after getting a block request
+ void applicationStoppedDueToBlock(const QString &appId);
+ // query function for the installer to verify that it is safe to manipulate binaries
+ bool areAllApplicationsStoppedDueToBlock() const;
+
+signals:
+ void bulkChange();
+ void stateChanged(State state);
+ void blockedChanged(bool blocked);
+
+private:
+ PackageInfo *m_info = nullptr;
+ PackageInfo *m_updatedInfo = nullptr;
+
+ State m_state = Installed;
+ qreal m_progress = 0;
+ QAtomicInt m_blocked;
+ QAtomicInt m_blockedAppsCount;
+ QVector<ApplicationInfo *> m_blockedApps;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/packagemanager.cpp b/src/manager-lib/packagemanager.cpp
new file mode 100644
index 00000000..6ccfd199
--- /dev/null
+++ b/src/manager-lib/packagemanager.cpp
@@ -0,0 +1,1321 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QMetaMethod>
+#include <QQmlEngine>
+#include <QVersionNumber>
+#include "packagemanager.h"
+#include "packagedatabase.h"
+#include "packagemanager_p.h"
+#include "applicationinfo.h"
+#include "intentinfo.h"
+#include "package.h"
+#include "logging.h"
+#include "installationreport.h"
+#include "exception.h"
+#include "sudo.h"
+#include "utilities.h"
+
+#if defined(Q_OS_WIN)
+# include <Windows.h>
+#else
+# include <sys/stat.h>
+# include <errno.h>
+# if defined(Q_OS_ANDROID)
+# include <sys/vfs.h>
+# define statvfs statfs
+# else
+# include <sys/statvfs.h>
+# endif
+#endif
+
+
+QT_BEGIN_NAMESPACE_AM
+
+enum Roles
+{
+ Id = Qt::UserRole,
+ Name,
+ Description,
+ Icon,
+
+ IsBlocked,
+ IsUpdating,
+ IsRemovable,
+
+ UpdateProgress,
+
+ Version,
+ PackageItem,
+};
+
+PackageManager *PackageManager::s_instance = nullptr;
+QHash<int, QByteArray> PackageManager::s_roleNames;
+
+PackageManager *PackageManager::createInstance(PackageDatabase *packageDatabase,
+ const QString &documentPath)
+{
+ if (Q_UNLIKELY(s_instance))
+ qFatal("PackageManager::createInstance() was called a second time.");
+
+ Q_ASSERT(packageDatabase);
+
+ QScopedPointer<PackageManager> pm(new PackageManager(packageDatabase, documentPath));
+ registerQmlTypes();
+
+ return s_instance = pm.take();
+}
+
+PackageManager *PackageManager::instance()
+{
+ if (!s_instance)
+ qFatal("PackageManager::instance() was called before createInstance().");
+ return s_instance;
+}
+
+QObject *PackageManager::instanceForQml(QQmlEngine *, QJSEngine *)
+{
+ QQmlEngine::setObjectOwnership(instance(), QQmlEngine::CppOwnership);
+ return instance();
+}
+
+void PackageManager::registerPackages()
+{
+ qCDebug(LogSystem) << "Registering packages:";
+
+ // collect all updates to builtin first, so we can avoid re-creating a lot of objects,
+ // if we find an update to a builin app later on
+ QMap<QString, QPair<PackageInfo *, PackageInfo *>> pkgs;
+
+ // map all the built-in packages first
+ const auto builtinPackages = d->database->builtInPackages();
+ for (auto packageInfo : builtinPackages) {
+ if (Package *existingPackage = fromId(packageInfo->id())) {
+ throw Exception(Error::Package, "Found more than one built-in package with id '%1': here: %2 and there: %3")
+ .arg(packageInfo->id())
+ .arg(existingPackage->info()->manifestPath())
+ .arg(packageInfo->manifestPath());
+ }
+ pkgs.insert(packageInfo->id(), qMakePair(packageInfo, nullptr));
+ }
+
+ // next, map all the installed packages, making sure to detect updates to built-in ones
+ const auto installedPackages = d->database->installedPackages();
+ for (auto packageInfo : installedPackages) {
+ auto existingPackageInfos = pkgs.value(packageInfo->id());
+ if (existingPackageInfos.first) {
+ if (existingPackageInfos.first->isBuiltIn()) { // update
+ if (existingPackageInfos.second) { // but there already is an update applied!?
+ throw Exception(Error::Package, "Found more than one update for the built-in package with id '%1' here: %2 and there: %3")
+ .arg(packageInfo->id())
+ .arg(existingPackageInfos.second->manifestPath())
+ .arg(packageInfo->manifestPath());
+ }
+ pkgs[packageInfo->id()] = qMakePair(existingPackageInfos.first, packageInfo);
+
+ } else {
+ throw Exception(Error::Package, "Found more than one installed package with the same id '%1' here: %2 and there: %3")
+ .arg(packageInfo->id())
+ .arg(existingPackageInfos.first->manifestPath())
+ .arg(packageInfo->manifestPath());
+ }
+ } else {
+ pkgs.insert(packageInfo->id(), qMakePair(packageInfo, nullptr));
+ }
+ }
+ for (auto it = pkgs.constBegin(); it != pkgs.constEnd(); ++it)
+ registerPackage(it.value().first, it.value().second);
+}
+
+void PackageManager::registerPackage(PackageInfo *packageInfo, PackageInfo *updatedPackageInfo,
+ bool currentlyBeingInstalled)
+{
+ auto *package = new Package(packageInfo, currentlyBeingInstalled ? Package::BeingInstalled
+ : Package::Installed);
+ if (updatedPackageInfo)
+ package->setUpdatedInfo(updatedPackageInfo);
+
+ QQmlEngine::setObjectOwnership(package, QQmlEngine::CppOwnership);
+
+ if (currentlyBeingInstalled) {
+ bool blocked = package->block();
+ Q_ASSERT(blocked);
+
+ beginInsertRows(QModelIndex(), d->packages.count(), d->packages.count());
+ qCDebug(LogSystem) << "Installing package:";
+ }
+
+ d->packages << package;
+
+ qCDebug(LogSystem).nospace().noquote() << " + package: " << package->id() << " [at: "
+ << QDir().relativeFilePath(package->info()->baseDir().path()) << "]";
+
+ if (currentlyBeingInstalled) {
+ endInsertRows();
+ emitDataChanged(package);
+ }
+
+ emit packageAdded(package->id());
+
+ if (!currentlyBeingInstalled)
+ registerApplicationsAndIntentsOfPackage(package);
+}
+
+void PackageManager::registerApplicationsAndIntentsOfPackage(Package *package)
+{
+ const auto appInfos = package->info()->applications();
+ for (auto appInfo : appInfos) {
+ try {
+ emit internalSignals.registerApplication(appInfo, package);
+ } catch (const Exception &e) {
+ qCWarning(LogSystem) << "Cannot register application" << appInfo->id() << ":"
+ << e.errorString();
+ }
+ }
+
+ const auto intentInfos = package->info()->intents();
+ for (auto intentInfo : intentInfos) {
+ try {
+ emit internalSignals.registerIntent(intentInfo, package);
+ } catch (const Exception &e) {
+ qCWarning(LogSystem) << "Cannot register intent" << intentInfo->id() << ":"
+ << e.errorString();
+ }
+ }
+}
+
+void PackageManager::unregisterApplicationsAndIntentsOfPackage(Package *package)
+{
+ const auto intentInfos = package->info()->intents();
+ for (auto intentInfo : intentInfos) {
+ try {
+ emit internalSignals.unregisterIntent(intentInfo, package); // not throwing ATM
+ } catch (const Exception &e) {
+ qCWarning(LogSystem) << "Cannot unregister intent" << intentInfo->id() << ":"
+ << e.errorString();
+ }
+ }
+
+ const auto appInfos = package->info()->applications();
+ for (auto appInfo : appInfos) {
+ try {
+ emit internalSignals.unregisterApplication(appInfo, package); // not throwing ATM
+ } catch (const Exception &e) {
+ qCWarning(LogSystem) << "Cannot unregister application" << appInfo->id() << ":"
+ << e.errorString();
+ }
+ }
+}
+
+QVector<Package *> PackageManager::packages() const
+{
+ return d->packages;
+}
+
+void PackageManager::registerQmlTypes()
+{
+ qmlRegisterSingletonType<PackageManager>("QtApplicationManager.SystemUI", 2, 0, "PackageManager",
+ &PackageManager::instanceForQml);
+ qmlRegisterUncreatableType<Package>("QtApplicationManager.SystemUI", 2, 0, "PackageObject",
+ qSL("Cannot create objects of type PackageObject"));
+ qRegisterMetaType<Package *>("Package*");
+
+ s_roleNames.insert(Id, "packageId");
+ s_roleNames.insert(Name, "name");
+ s_roleNames.insert(Description, "description");
+ s_roleNames.insert(Icon, "icon");
+ s_roleNames.insert(IsBlocked, "isBlocked");
+ s_roleNames.insert(IsUpdating, "isUpdating");
+ s_roleNames.insert(IsRemovable, "isRemovable");
+ s_roleNames.insert(UpdateProgress, "updateProgress");
+ s_roleNames.insert(Version, "version");
+ s_roleNames.insert(PackageItem, "package");
+}
+
+PackageManager::PackageManager(PackageDatabase *packageDatabase,
+ const QString &documentPath)
+ : QAbstractListModel()
+ , d(new PackageManagerPrivate())
+{
+ d->database = packageDatabase;
+ d->installationPath = packageDatabase->installedPackagesDir();
+ d->documentPath = documentPath;
+}
+
+PackageManager::~PackageManager()
+{
+ qDeleteAll(d->packages);
+ delete d->database;
+ delete d;
+ s_instance = nullptr;
+}
+
+Package *PackageManager::fromId(const QString &id) const
+{
+ for (auto package : d->packages) {
+ if (package->id() == id)
+ return package;
+ }
+ return nullptr;
+}
+
+void PackageManager::emitDataChanged(Package *package, const QVector<int> &roles)
+{
+ int row = d->packages.indexOf(package);
+ if (row >= 0) {
+ emit dataChanged(index(row), index(row), roles);
+
+ static const auto pkgChanged = QMetaMethod::fromSignal(&PackageManager::packageChanged);
+ if (isSignalConnected(pkgChanged)) {
+ QStringList stringRoles;
+ for (auto role : roles)
+ stringRoles << qL1S(s_roleNames[role]);
+ emit packageChanged(package->id(), stringRoles);
+ }
+ }
+}
+
+// item model part
+
+int PackageManager::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+ return d->packages.count();
+}
+
+QVariant PackageManager::data(const QModelIndex &index, int role) const
+{
+ if (index.parent().isValid() || !index.isValid())
+ return QVariant();
+
+ Package *package = d->packages.at(index.row());
+
+ switch (role) {
+ case Id:
+ return package->id();
+ case Name:
+ return package->name();
+ case Description:
+ return package->description();
+ case Icon:
+ return package->icon();
+ case IsBlocked:
+ return package->isBlocked();
+ case IsUpdating:
+ return package->state() != Package::Installed;
+ case UpdateProgress:
+ return package->progress();
+ case IsRemovable:
+ return !package->isBuiltIn();
+ case Version:
+ return package->version();
+ case PackageItem:
+ return QVariant::fromValue(package);
+ }
+ return QVariant();
+}
+
+QHash<int, QByteArray> PackageManager::roleNames() const
+{
+ return s_roleNames;
+}
+
+int PackageManager::count() const
+{
+ return rowCount();
+}
+
+/*!
+ \qmlmethod object PackageManager::get(int index)
+
+ Retrieves the model data at \a index as a JavaScript object. See the
+ \l {PackageManager Roles}{role names} for the expected object fields.
+
+ Returns an empty object if the specified \a index is invalid.
+
+ \note This is very inefficient if you only want to access a single property from QML; use
+ package() instead to access the Package object's properties directly.
+*/
+QVariantMap PackageManager::get(int index) const
+{
+ if (index < 0 || index >= count()) {
+ qCWarning(LogSystem) << "PackageManager::get(index): invalid index:" << index;
+ return QVariantMap();
+ }
+
+ QVariantMap map;
+ QHash<int, QByteArray> roles = roleNames();
+ for (auto it = roles.begin(); it != roles.end(); ++it)
+ map.insert(qL1S(it.value()), data(this->index(index), it.key()));
+ return map;
+}
+
+/*!
+ \qmlmethod PackageObject PackageManager::package(int index)
+
+ Returns the \l{PackageObject}{package} corresponding to the given \a index in the
+ model, or \c null if the index is invalid.
+
+ \note The object ownership of the returned Package object stays with the application-manager.
+ If you want to store this pointer, you can use the PackageManager's QAbstractListModel
+ signals or the packageAboutToBeRemoved signal to get notified if the object is about
+ to be deleted on the C++ side.
+*/
+Package *PackageManager::package(int index) const
+{
+ if (index < 0 || index >= count()) {
+ qCWarning(LogSystem) << "PackageManager::application(index): invalid index:" << index;
+ return nullptr;
+ }
+ return d->packages.at(index);
+}
+
+/*!
+ \qmlmethod PackageObject PackageManager::package(string id)
+
+ Returns the \l{PackageObject}{package} corresponding to the given package \a id,
+ or \c null if the id does not exist.
+
+ \note The object ownership of the returned Package object stays with the application-manager.
+ If you want to store this pointer, you can use the PackageManager's QAbstractListModel
+ signals or the packageAboutToBeRemoved signal to get notified if the object is about
+ to be deleted on the C++ side.
+*/
+Package *PackageManager::package(const QString &id) const
+{
+ auto index = indexOfPackage(id);
+ return (index < 0) ? nullptr : package(index);
+}
+
+/*!
+ \qmlmethod int PackageManager::indexOfPackage(string id)
+
+ Maps the package \a id to its position within the model.
+
+ Returns \c -1 if the specified \a id is invalid.
+*/
+int PackageManager::indexOfPackage(const QString &id) const
+{
+ for (int i = 0; i < d->packages.size(); ++i) {
+ if (d->packages.at(i)->id() == id)
+ return i;
+ }
+ return -1;
+}
+
+bool PackageManager::developmentMode() const
+{
+ return d->developmentMode;
+}
+
+void PackageManager::setDevelopmentMode(bool enable)
+{
+ d->developmentMode = enable;
+}
+
+bool PackageManager::allowInstallationOfUnsignedPackages() const
+{
+ return d->allowInstallationOfUnsignedPackages;
+}
+
+void PackageManager::setAllowInstallationOfUnsignedPackages(bool enable)
+{
+ d->allowInstallationOfUnsignedPackages = enable;
+}
+
+QString PackageManager::hardwareId() const
+{
+ return d->hardwareId;
+}
+
+void PackageManager::setHardwareId(const QString &hwId)
+{
+ d->hardwareId = hwId;
+}
+
+bool PackageManager::isApplicationUserIdSeparationEnabled() const
+{
+ return d->userIdSeparation;
+}
+
+uint PackageManager::commonApplicationGroupId() const
+{
+ return d->commonGroupId;
+}
+
+bool PackageManager::enableApplicationUserIdSeparation(uint minUserId, uint maxUserId, uint commonGroupId)
+{
+ if (minUserId >= maxUserId || minUserId == uint(-1) || maxUserId == uint(-1))
+ return false;
+ d->userIdSeparation = true;
+ d->minUserId = minUserId;
+ d->maxUserId = maxUserId;
+ d->commonGroupId = commonGroupId;
+ return true;
+}
+
+uint PackageManager::findUnusedUserId() const Q_DECL_NOEXCEPT_EXPR(false)
+{
+ if (!isApplicationUserIdSeparationEnabled())
+ return uint(-1);
+
+ for (uint uid = d->minUserId; uid <= d->maxUserId; ++uid) {
+ bool match = false;
+ for (Package *package : d->packages) {
+ if (package->info()->uid() == uid) {
+ match = true;
+ break;
+ }
+ }
+ if (!match)
+ return uid;
+ }
+ throw Exception("could not find a free user-id for application separation in the range %1 to %2")
+ .arg(d->minUserId).arg(d->maxUserId);
+}
+
+QList<QByteArray> PackageManager::caCertificates() const
+{
+ return d->chainOfTrust;
+}
+
+void PackageManager::setCACertificates(const QList<QByteArray> &chainOfTrust)
+{
+ d->chainOfTrust = chainOfTrust;
+}
+
+static QVariantMap locationMap(const QString &path)
+{
+ QString cpath = QFileInfo(path).canonicalPath();
+ quint64 bytesTotal = 0;
+ quint64 bytesFree = 0;
+
+#if defined(Q_OS_WIN)
+ GetDiskFreeSpaceExW((LPCWSTR) cpath.utf16(), (ULARGE_INTEGER *) &bytesFree,
+ (ULARGE_INTEGER *) &bytesTotal, nullptr);
+
+#else // Q_OS_UNIX
+ int result;
+ struct ::statvfs svfs;
+
+ do {
+ result = ::statvfs(cpath.toLocal8Bit(), &svfs);
+ if (result == -1 && errno == EINTR)
+ continue;
+ } while (false);
+
+ if (result == 0) {
+ bytesTotal = quint64(svfs.f_frsize) * svfs.f_blocks;
+ bytesFree = quint64(svfs.f_frsize) * svfs.f_bavail;
+ }
+#endif // Q_OS_WIN
+
+
+ return QVariantMap {
+ { qSL("path"), path },
+ { qSL("deviceSize"), bytesTotal },
+ { qSL("deviceFree"), bytesFree }
+ };
+}
+
+/*!
+ \qmlproperty object PackageManager::installationLocation
+
+ Returns an object describing the location under which applications are installed in detail.
+
+ The returned object has the following members:
+
+ \table
+ \header
+ \li \c Name
+ \li \c Type
+ \li Description
+ \row
+ \li \c path
+ \li \c string
+ \li The absolute file-system path to the base directory.
+ \row
+ \li \c deviceSize
+ \li \c int
+ \li The size of the device holding \c path in bytes.
+ \row
+ \li \c deviceFree
+ \li \c int
+ \li The amount of bytes available on the device holding \c path.
+ \endtable
+
+ Returns an empty object in case the installer component is disabled.
+*/
+QVariantMap PackageManager::installationLocation() const
+{
+ return locationMap(d->installationPath);
+}
+
+/*!
+ \qmlproperty object PackageManager::documentLocation
+
+ Returns an object describing the location under which per-user document
+ directories are created in detail.
+
+ The returned object has the same members as described in PackageManager::installationLocation.
+*/
+QVariantMap PackageManager::documentLocation() const
+{
+ return locationMap(d->documentPath);
+}
+
+void PackageManager::cleanupBrokenInstallations() Q_DECL_NOEXCEPT_EXPR(false)
+{
+ // Check that everything in the app-db is available
+ // -> if not, remove from app-db
+
+ // key: baseDirPath, value: subDirName/ or fileName
+ QMultiMap<QString, QString> validPaths;
+ if (!d->documentPath.isEmpty())
+ validPaths.insert(d->documentPath, QString());
+ if (!d->installationPath.isEmpty())
+ validPaths.insert(d->installationPath, QString());
+
+ for (Package *pkg : d->packages) { // we want to detach here!
+ const InstallationReport *ir = pkg->info()->installationReport();
+ if (ir) {
+ bool valid = true;
+
+ QString pkgDir = d->installationPath + QDir::separator() + pkg->id();
+ QStringList checkDirs;
+ QStringList checkFiles;
+
+ checkFiles << pkgDir + qSL("/info.yaml");
+ checkFiles << pkgDir + qSL("/.installation-report.yaml");
+ checkDirs << pkgDir;
+
+ for (const QString &checkFile : qAsConst(checkFiles)) {
+ QFileInfo fi(checkFile);
+ if (!fi.exists() || !fi.isFile() || !fi.isReadable()) {
+ valid = false;
+ qCDebug(LogInstaller) << "cleanup: uninstalling" << pkg->id() << "- file missing:" << checkFile;
+ break;
+ }
+ }
+ for (const QString &checkDir : checkDirs) {
+ QFileInfo fi(checkDir);
+ if (!fi.exists() || !fi.isDir() || !fi.isReadable()) {
+ valid = false;
+ qCDebug(LogInstaller) << "cleanup: uninstalling" << pkg->id() << "- directory missing:" << checkDir;
+ break;
+ }
+ }
+
+ if (valid) {
+ validPaths.insertMulti(d->installationPath, pkg->id() + QDir::separator());
+ validPaths.insertMulti(d->documentPath, pkg->id() + QDir::separator());
+ } else {
+ if (startingPackageRemoval(pkg->id())) {
+ if (finishedPackageInstall(pkg->id()))
+ continue;
+ }
+ throw Exception(Error::Package, "could not remove broken installation of package %1 from database").arg(pkg->id());
+ }
+ }
+ }
+
+ // Remove everything that is not referenced from the app-db
+
+ for (auto it = validPaths.cbegin(); it != validPaths.cend(); ) {
+ const QString currentDir = it.key();
+
+ // collect all values for the unique key currentDir
+ QVector<QString> validNames;
+ for ( ; it != validPaths.cend() && it.key() == currentDir; ++it)
+ validNames << it.value();
+
+ const QFileInfoList &dirEntries = QDir(currentDir).entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot);
+
+ // check if there is anything in the filesystem that is NOT listed in the validNames
+ for (const QFileInfo &fi : dirEntries) {
+ QString name = fi.fileName();
+ if (fi.isDir())
+ name.append(QDir::separator());
+
+ if ((!fi.isDir() && !fi.isFile()) || !validNames.contains(name)) {
+ qCDebug(LogInstaller) << "cleanup: removing unreferenced inode" << name;
+
+ if (SudoClient::instance()) {
+ if (!SudoClient::instance()->removeRecursive(fi.absoluteFilePath())) {
+ throw Exception(Error::IO, "could not remove broken installation leftover %1: %2")
+ .arg(fi.absoluteFilePath()).arg(SudoClient::instance()->lastError());
+ }
+ } else {
+ if (!recursiveOperation(fi.absoluteFilePath(), safeRemove)) {
+ throw Exception(Error::IO, "could not remove broken installation leftover %1 (maybe due to missing root privileges)")
+ .arg(fi.absoluteFilePath());
+ }
+ }
+ }
+ }
+ }
+}
+
+/*!
+ \qmlmethod list<string> PackageManager::packageIds()
+
+ Returns a list of all available package ids. This can be used to further query for specific
+ information via get().
+*/
+QStringList PackageManager::packageIds() const
+{
+ QStringList ids;
+ ids.reserve(d->packages.size());
+ for (int i = 0; i < d->packages.size(); ++i)
+ ids << d->packages.at(i)->id();
+ return ids;
+}
+
+/*!
+ \qmlmethod object PackageManager::get(string id)
+
+ Retrieves the model data for the package identified by \a id as a JavaScript object.
+ See the \l {PackageManager Roles}{role names} for the expected object fields.
+
+ Returns an empty object if the specified \a id is invalid.
+*/
+QVariantMap PackageManager::get(const QString &id) const
+{
+ int index = indexOfPackage(id);
+ return (index < 0) ? QVariantMap{} : get(index);
+}
+
+/*!
+ \qmlmethod int PackageManager::installedPackageSize(string packageId)
+
+ Returns the size in bytes that the package identified by \a packageId is occupying on the storage
+ device.
+
+ Returns \c -1 in case the package \a packageId is not valid, or the package is not installed.
+*/
+qint64 PackageManager::installedPackageSize(const QString &packageId) const
+{
+ if (Package *package = fromId(packageId)) {
+ if (const InstallationReport *report = package->info()->installationReport())
+ return static_cast<qint64>(report->diskSpaceUsed());
+ }
+ return -1;
+}
+
+/*!
+ \qmlmethod var PackageManager::installedPackageExtraMetaData(string packageId)
+
+ Returns a map of all extra metadata in the package header of the package identified by \a packageId.
+
+ Returns an empty map in case the package \a packageId is not valid, or the package is not installed.
+*/
+QVariantMap PackageManager::installedPackageExtraMetaData(const QString &packageId) const
+{
+ if (Package *package = fromId(packageId)) {
+ if (const InstallationReport *report = package->info()->installationReport())
+ return report->extraMetaData();
+ }
+ return QVariantMap();
+}
+
+/*!
+ \qmlmethod var PackageManager::installedPackageExtraSignedMetaData(string packageId)
+
+ Returns a map of all signed extra metadata in the package header of the package identified
+ by \a packageId.
+
+ Returns an empty map in case the package \a packageId is not valid, or the package is not installed.
+*/
+QVariantMap PackageManager::installedPackageExtraSignedMetaData(const QString &packageId) const
+{
+ if (Package *package = fromId(packageId)) {
+ if (const InstallationReport *report = package->info()->installationReport())
+ return report->extraSignedMetaData();
+ }
+ return QVariantMap();
+}
+
+/*! \internal
+ Type safe convenience function, since DBus does not like QUrl
+*/
+QString PackageManager::startPackageInstallation(const QUrl &sourceUrl)
+{
+ AM_TRACE(LogInstaller, sourceUrl);
+
+ return enqueueTask(new InstallationTask(d->installationPath, d->documentPath, sourceUrl));
+}
+
+/*!
+ \qmlmethod string PackageManager::startPackageInstallation(string sourceUrl)
+
+ Downloads an application package from \a sourceUrl and installs it.
+
+ The actual download and installation will happen asynchronously in the background. The
+ PackageManager emits the signals \l taskStarted, \l taskProgressChanged, \l
+ taskRequestingInstallationAcknowledge, \l taskFinished, \l taskFailed, and \l taskStateChanged
+ for the returned taskId when applicable.
+
+ \note Simply calling this function is not enough to complete a package installation: The
+ taskRequestingInstallationAcknowledge() signal needs to be connected to a slot where the
+ supplied package meta-data can be validated (either programmatically or by asking the user).
+ If the validation is successful, the installation can be completed by calling
+ acknowledgePackageInstallation() or, if the validation was unsuccessful, the installation should
+ be canceled by calling cancelTask().
+ Failing to do one or the other will leave an unfinished "zombie" installation.
+
+ Returns a unique \c taskId. This can also be an empty string, if the task could not be
+ created (in this case, no signals will be emitted).
+*/
+QString PackageManager::startPackageInstallation(const QString &sourceUrl)
+{
+ QUrl url(sourceUrl);
+ if (url.scheme().isEmpty())
+ url = QUrl::fromLocalFile(sourceUrl);
+ return startPackageInstallation(url);
+}
+
+/*!
+ \qmlmethod void PackageManager::acknowledgePackageInstallation(string taskId)
+
+ Calling this function enables the installer to complete the installation task identified by \a
+ taskId. Normally, this function is called after receiving the taskRequestingInstallationAcknowledge()
+ signal, and the user and/or the program logic decided to proceed with the installation.
+
+ \sa startPackageInstallation()
+ */
+void PackageManager::acknowledgePackageInstallation(const QString &taskId)
+{
+ AM_TRACE(LogInstaller, taskId)
+
+ const auto allTasks = d->allTasks();
+
+ for (AsynchronousTask *task : allTasks) {
+ if (qobject_cast<InstallationTask *>(task) && (task->id() == taskId)) {
+ static_cast<InstallationTask *>(task)->acknowledge();
+ break;
+ }
+ }
+}
+
+/*!
+ \qmlmethod string PackageManager::removePackage(string packageId, bool keepDocuments, bool force)
+
+ Uninstalls the package identified by \a id. Normally, the documents directory of the
+ package is deleted on removal, but this can be prevented by setting \a keepDocuments to \c true.
+
+ The actual removal will happen asynchronously in the background. The PackageManager will
+ emit the signals \l taskStarted, \l taskProgressChanged, \l taskFinished, \l taskFailed and \l
+ taskStateChanged for the returned \c taskId when applicable.
+
+ Normally, \a force should only be set to \c true if a previous call to removePackage() failed.
+ This may be necessary if the installation process was interrupted, or or has file-system issues.
+
+ Returns a unique \c taskId. This can also be an empty string, if the task could not be created
+ (in this case, no signals will be emitted).
+*/
+QString PackageManager::removePackage(const QString &packageId, bool keepDocuments, bool force)
+{
+ AM_TRACE(LogInstaller, packageId, keepDocuments)
+
+ if (Package *package = fromId(packageId)) {
+ if (package->info()->installationReport()) {
+ return enqueueTask(new DeinstallationTask(package, d->installationPath,
+ d->documentPath, force, keepDocuments));
+ }
+ }
+ return QString();
+}
+
+
+/*!
+ \qmlmethod enumeration PackageManager::taskState(string taskId)
+
+ Returns the current state of the installation task identified by \a taskId.
+ \l {TaskStates}{See here} for a list of valid task states.
+
+ Returns \c PackageManager.Invalid if the \a taskId is invalid.
+*/
+AsynchronousTask::TaskState PackageManager::taskState(const QString &taskId) const
+{
+ const auto allTasks = d->allTasks();
+
+ for (const AsynchronousTask *task : allTasks) {
+ if (task && (task->id() == taskId))
+ return task->state();
+ }
+ return AsynchronousTask::Invalid;
+}
+
+/*!
+ \qmlmethod string PackageManager::taskPackageId(string taskId)
+
+ Returns the package id associated with the task identified by \a taskId. The task may not
+ have a valid package id at all times though and in this case the function will return an
+ empty string (this will be the case for installations before the taskRequestingInstallationAcknowledge
+ signal has been emitted).
+
+ Returns an empty string if the \a taskId is invalid.
+*/
+QString PackageManager::taskPackageId(const QString &taskId) const
+{
+ const auto allTasks = d->allTasks();
+
+ for (const AsynchronousTask *task : allTasks) {
+ if (task && (task->id() == taskId))
+ return task->packageId();
+ }
+ return QString();
+}
+
+/*!
+ \qmlmethod list<string> PackageManager::activeTaskIds()
+
+ Retuns a list of all currently active (as in not yet finished or failed) installation task ids.
+*/
+QStringList PackageManager::activeTaskIds() const
+{
+ const auto allTasks = d->allTasks();
+
+ QStringList result;
+ for (const AsynchronousTask *task : allTasks)
+ result << task->id();
+ return result;
+}
+
+/*!
+ \qmlmethod bool PackageManager::cancelTask(string taskId)
+
+ Tries to cancel the installation task identified by \a taskId.
+
+ Returns \c true if the task was canceled, \c false otherwise.
+*/
+bool PackageManager::cancelTask(const QString &taskId)
+{
+ AM_TRACE(LogInstaller, taskId)
+
+ // incoming tasks can be forcefully cancelled right away
+ for (AsynchronousTask *task : qAsConst(d->incomingTaskList)) {
+ if (task->id() == taskId) {
+ task->forceCancel();
+ task->deleteLater();
+
+ handleFailure(task);
+
+ d->incomingTaskList.removeOne(task);
+ triggerExecuteNextTask();
+ return true;
+ }
+ }
+
+ // the active task and async tasks might be in a state where cancellation is not possible,
+ // so we have to ask them nicely
+ if (d->activeTask && d->activeTask->id() == taskId)
+ return d->activeTask->cancel();
+
+ for (AsynchronousTask *task : qAsConst(d->installationTaskList)) {
+ if (task->id() == taskId)
+ return task->cancel();
+ }
+ return false;
+}
+
+/*!
+ \qmlmethod int PackageManager::compareVersions(string version1, string version2)
+
+ Convenience method for app-store implementations or taskRequestingInstallationAcknowledge()
+ callbacks for comparing version numbers, as the actual version comparison algorithm is not
+ trivial.
+
+ Returns \c -1, \c 0 or \c 1 if \a version1 is smaller than, equal to, or greater than \a
+ version2 (similar to how \c strcmp() works).
+*/
+int PackageManager::compareVersions(const QString &version1, const QString &version2)
+{
+ int vn1Suffix = -1;
+ int vn2Suffix = -1;
+ QVersionNumber vn1 = QVersionNumber::fromString(version1, &vn1Suffix);
+ QVersionNumber vn2 = QVersionNumber::fromString(version2, &vn2Suffix);
+
+ int d = QVersionNumber::compare(vn1, vn2);
+ return d < 0 ? -1 : (d > 0 ? 1 : version1.mid(vn1Suffix).compare(version2.mid(vn2Suffix)));
+}
+
+/*!
+ \qmlmethod int PackageManager::validateDnsName(string name, int minimalPartCount)
+
+ Convenience method for app-store implementations or taskRequestingInstallationAcknowledge()
+ callbacks for checking if the given \a name is a valid DNS (or reverse-DNS) name according to
+ RFC 1035/1123. If the optional parameter \a minimalPartCount is specified, this function will
+ also check if \a name contains at least this amount of parts/sub-domains.
+
+ Returns \c true if the name is a valid DNS name or \c false otherwise.
+*/
+bool PackageManager::validateDnsName(const QString &name, int minimalPartCount)
+{
+ try {
+ // check if we have enough parts: e.g. "tld.company.app" would have 3 parts
+ QStringList parts = name.split('.');
+ if (parts.size() < minimalPartCount) {
+ throw Exception(Error::Parse, "the minimum amount of parts (subdomains) is %1 (found %2)")
+ .arg(minimalPartCount).arg(parts.size());
+ }
+
+ // standard RFC compliance tests (RFC 1035/1123)
+
+ auto partCheck = [](const QString &part) {
+ int len = part.length();
+
+ if (len < 1 || len > 63)
+ throw Exception(Error::Parse, "domain parts must consist of at least 1 and at most 63 characters (found %2 characters)").arg(len);
+
+ for (int pos = 0; pos < len; ++pos) {
+ ushort ch = part.at(pos).unicode();
+ bool isFirst = (pos == 0);
+ bool isLast = (pos == (len - 1));
+ bool isDash = (ch == '-');
+ bool isDigit = (ch >= '0' && ch <= '9');
+ bool isLower = (ch >= 'a' && ch <= 'z');
+
+ if ((isFirst || isLast || !isDash) && !isDigit && !isLower)
+ throw Exception(Error::Parse, "domain parts must consist of only the characters '0-9', 'a-z', and '-' (which cannot be the first or last character)");
+ }
+ };
+
+ for (const QString &part : parts)
+ partCheck(part);
+
+ return true;
+ } catch (const Exception &e) {
+ qCDebug(LogInstaller).noquote() << "validateDnsName failed:" << e.errorString();
+ return false;
+ }
+}
+
+QString PackageManager::enqueueTask(AsynchronousTask *task)
+{
+ d->incomingTaskList.append(task);
+ triggerExecuteNextTask();
+ return task->id();
+}
+
+void PackageManager::triggerExecuteNextTask()
+{
+ if (!QMetaObject::invokeMethod(this, "executeNextTask", Qt::QueuedConnection))
+ qCCritical(LogSystem) << "ERROR: failed to invoke method checkQueue";
+}
+
+void PackageManager::executeNextTask()
+{
+ if (d->activeTask || d->incomingTaskList.isEmpty())
+ return;
+
+ AsynchronousTask *task = d->incomingTaskList.takeFirst();
+
+ if (task->hasFailed()) {
+ task->setState(AsynchronousTask::Failed);
+
+ handleFailure(task);
+
+ task->deleteLater();
+ triggerExecuteNextTask();
+ return;
+ }
+
+ connect(task, &AsynchronousTask::started, this, [this, task]() {
+ emit taskStarted(task->id());
+ });
+
+ connect(task, &AsynchronousTask::stateChanged, this, [this, task](AsynchronousTask::TaskState newState) {
+ emit taskStateChanged(task->id(), newState);
+ });
+
+ connect(task, &AsynchronousTask::progress, this, [this, task](qreal p) {
+ emit taskProgressChanged(task->id(), p);
+
+ Package *package = fromId(task->packageId());
+ if (package && (package->state() != Package::Installed)) {
+ package->setProgress(p);
+ // Icon will be in a "+" suffixed directory during installation. So notify about a change on its
+ // location as well.
+ emitDataChanged(package, QVector<int> { Icon, UpdateProgress });
+ }
+ });
+
+ connect(task, &AsynchronousTask::finished, this, [this, task]() {
+ task->setState(task->hasFailed() ? AsynchronousTask::Failed : AsynchronousTask::Finished);
+
+ if (task->hasFailed()) {
+ handleFailure(task);
+ } else {
+ qCDebug(LogInstaller) << "emit finished" << task->id();
+ emit taskFinished(task->id());
+ }
+
+ if (d->activeTask == task)
+ d->activeTask = nullptr;
+ d->installationTaskList.removeOne(task);
+
+ delete task;
+ triggerExecuteNextTask();
+ });
+
+ if (qobject_cast<InstallationTask *>(task)) {
+ connect(static_cast<InstallationTask *>(task), &InstallationTask::finishedPackageExtraction, this, [this, task]() {
+ qCDebug(LogInstaller) << "emit blockingUntilInstallationAcknowledge" << task->id();
+ emit taskBlockingUntilInstallationAcknowledge(task->id());
+
+ // we can now start the next download in parallel - the InstallationTask will take care
+ // of serializing the final installation steps on its own as soon as it gets the
+ // required acknowledge (or cancel).
+ if (d->activeTask == task)
+ d->activeTask = nullptr;
+ d->installationTaskList.append(task);
+ triggerExecuteNextTask();
+ });
+ }
+
+
+ d->activeTask = task;
+ task->setState(AsynchronousTask::Executing);
+ task->start();
+}
+
+void PackageManager::handleFailure(AsynchronousTask *task)
+{
+ qCDebug(LogInstaller) << "emit failed" << task->id() << task->errorCode() << task->errorString();
+ emit taskFailed(task->id(), int(task->errorCode()), task->errorString());
+}
+
+bool PackageManager::startingPackageInstallation(PackageInfo *info)
+{
+ // ownership of info is transferred to PackageManager
+ QScopedPointer<PackageInfo> newInfo(info);
+
+ if (!newInfo || newInfo->id().isEmpty())
+ return false;
+
+ Package *package = fromId(newInfo->id());
+
+ if (package) { // update
+ if (!package->block())
+ return false;
+
+ // do not overwrite the base-info / update-info yet - only after a successful installation
+ d->pendingPackageInfoUpdates.insert(package, newInfo.take());
+
+ package->setState(Package::BeingUpdated);
+ package->setProgress(0);
+ emitDataChanged(package);
+ } else { // installation
+ // add a new package to the model and block it
+ registerPackage(newInfo.take(), nullptr, true);
+ }
+ return true;
+}
+
+bool PackageManager::startingPackageRemoval(const QString &id)
+{
+ Package *package = fromId(id);
+ if (!package)
+ return false;
+
+ if (package->isBlocked() || (package->state() != Package::Installed))
+ return false;
+
+ if (package->isBuiltIn() && !package->builtInHasRemovableUpdate())
+ return false;
+
+ if (!package->block()) // this will implicitly stop all apps in this package (asynchronously)
+ return false;
+
+ package->setState(package->builtInHasRemovableUpdate() ? Package::BeingDowngraded
+ : Package::BeingRemoved);
+
+ package->setProgress(0);
+ emitDataChanged(package, QVector<int> { IsUpdating });
+ return true;
+}
+
+bool PackageManager::finishedPackageInstall(const QString &id)
+{
+ Package *package = fromId(id);
+ if (!package)
+ return false;
+
+ switch (package->state()) {
+ case Package::Installed:
+ return false;
+
+ case Package::BeingUpdated:
+ case Package::BeingInstalled:
+ case Package::BeingDowngraded: {
+ bool isUpdate = (package->state() == Package::BeingUpdated);
+ bool isDowngrade = (package->state() == Package::BeingDowngraded);
+
+ // figure out what the new info is
+ PackageInfo *newPackageInfo;
+ if (isUpdate)
+ newPackageInfo = d->pendingPackageInfoUpdates.take(package);
+ else if (isDowngrade)
+ newPackageInfo = nullptr;
+ else
+ newPackageInfo = package->baseInfo();
+
+ // attach the installation report (unless we're just downgrading a built-in)
+ if (!isDowngrade) {
+ QFile irfile(newPackageInfo->baseDir().absoluteFilePath(qSL(".installation-report.yaml")));
+ QScopedPointer<InstallationReport> ir(new InstallationReport(package->id()));
+ irfile.open(QFile::ReadOnly);
+ try {
+ ir->deserialize(&irfile);
+ } catch (const Exception &e) {
+ qCCritical(LogInstaller) << "Could not read the new installation-report for package"
+ << package->id() << "at" << irfile.fileName() << ":"
+ << e.errorString();
+ return false;
+ }
+ newPackageInfo->setInstallationReport(ir.take());
+ }
+
+ if (isUpdate || isDowngrade) {
+ // unregister all the old apps & intents
+ unregisterApplicationsAndIntentsOfPackage(package);
+
+ // update the correct base/updated info pointer
+ PackageInfo *oldPackageInfo;
+ if (package->isBuiltIn())
+ oldPackageInfo = package->setUpdatedInfo(newPackageInfo);
+ else
+ oldPackageInfo = package->setBaseInfo(newPackageInfo);
+
+ if (oldPackageInfo)
+ d->database->removePackageInfo(oldPackageInfo);
+ }
+
+ // add the new info to the package db
+ if (newPackageInfo)
+ d->database->addPackageInfo(newPackageInfo);
+
+ // register all the apps & intents
+ registerApplicationsAndIntentsOfPackage(package);
+
+ // boiler-plate cleanup code
+ package->setState(Package::Installed);
+ package->setProgress(0);
+ emitDataChanged(package);
+ package->unblock();
+ emit package->bulkChange(); // not ideal, but icon and codeDir have changed
+ break;
+ }
+
+ case Package::BeingRemoved: {
+ // unregister all the apps & intents
+ unregisterApplicationsAndIntentsOfPackage(package);
+
+ // remove the package from the model
+ int row = d->packages.indexOf(package);
+ if (row >= 0) {
+ emit packageAboutToBeRemoved(package->id());
+ beginRemoveRows(QModelIndex(), row, row);
+ d->packages.removeAt(row);
+ endRemoveRows();
+ }
+
+ // cleanup
+ package->unblock();
+ delete package;
+
+ // remove the package from the package db
+ d->database->removePackageInfo(package->info());
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool PackageManager::canceledPackageInstall(const QString &id)
+{
+ Package *package = fromId(id);
+ if (!package)
+ return false;
+
+ switch (package->state()) {
+ case Package::Installed:
+ return false;
+
+ case Package::BeingInstalled: {
+ int row = d->packages.indexOf(package);
+ if (row >= 0) {
+ emit packageAboutToBeRemoved(package->id());
+ beginRemoveRows(QModelIndex(), row, row);
+ d->packages.removeAt(row);
+ endRemoveRows();
+ }
+ package->unblock();
+ delete package;
+ break;
+ }
+ case Package::BeingUpdated:
+ case Package::BeingDowngraded:
+ case Package::BeingRemoved:
+ package->setState(Package::Installed);
+ package->setProgress(0);
+ emitDataChanged(package, QVector<int> { IsUpdating });
+
+ package->unblock();
+ break;
+ }
+ return true;
+}
+
+bool removeRecursiveHelper(const QString &path)
+{
+ if (PackageManager::instance()->isApplicationUserIdSeparationEnabled() && SudoClient::instance())
+ return SudoClient::instance()->removeRecursive(path);
+ else
+ return recursiveOperation(path, safeRemove);
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/packagemanager.h b/src/manager-lib/packagemanager.h
new file mode 100644
index 00000000..082fc5e3
--- /dev/null
+++ b/src/manager-lib/packagemanager.h
@@ -0,0 +1,235 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QAbstractListModel>
+#include <QtAppManCommon/global.h>
+#include <QtAppManApplication/packageinfo.h>
+#include <QtAppManManager/asynchronoustask.h>
+#include <QtAppManManager/installationtask.h>
+#include <QtAppManManager/deinstallationtask.h>
+
+
+QT_FORWARD_DECLARE_CLASS(QQmlEngine)
+QT_FORWARD_DECLARE_CLASS(QJSEngine)
+
+QT_BEGIN_NAMESPACE_AM
+
+class PackageDatabase;
+class Package;
+class PackageManagerPrivate;
+
+// A place to collect signals used internally by appman without polluting
+// PackageManager's public QML API.
+class PackageManagerInternalSignals : public QObject
+{
+ Q_OBJECT
+signals:
+ // the slots connected to these signals are allowed to throw Exception objects, if the
+ // connection is direct!
+ void registerApplication(ApplicationInfo *applicationInfo, Package *package);
+ void unregisterApplication(ApplicationInfo *applicationInfo, Package *package);
+
+ void registerIntent(IntentInfo *intentInfo, Package *package);
+ void unregisterIntent(IntentInfo *intentInfo, Package *package);
+};
+
+class PackageManager : public QAbstractListModel
+{
+ Q_OBJECT
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_CLASSINFO("D-Bus Interface", "io.qt.PackageManager")
+ Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/PackageManager 2.0 SINGLETON")
+
+ // these are const on purpose - these should never change in a running system
+ Q_PROPERTY(bool allowInstallationOfUnsignedPackages READ allowInstallationOfUnsignedPackages CONSTANT)
+ Q_PROPERTY(bool developmentMode READ developmentMode CONSTANT)
+ Q_PROPERTY(QString hardwareId READ hardwareId CONSTANT)
+
+ Q_PROPERTY(QVariantMap installationLocation READ installationLocation CONSTANT)
+ Q_PROPERTY(QVariantMap documentLocation READ documentLocation CONSTANT)
+
+ Q_PROPERTY(bool applicationUserIdSeparation READ isApplicationUserIdSeparationEnabled)
+ Q_PROPERTY(uint commonApplicationGroupId READ commonApplicationGroupId)
+
+public:
+ Q_ENUMS(QT_PREPEND_NAMESPACE_AM(AsynchronousTask::TaskState))
+
+ enum CacheMode {
+ NoCache,
+ UseCache,
+ RecreateCache
+ };
+
+ ~PackageManager() override;
+ static PackageManager *createInstance(PackageDatabase *packageDatabase,
+ const QString &documentPath);
+ static PackageManager *instance();
+ static QObject *instanceForQml(QQmlEngine *qmlEngine, QJSEngine *);
+
+ void registerPackages();
+
+ QVector<Package *> packages() const;
+
+ Package *fromId(const QString &id) const;
+
+ // the item model part
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ QHash<int, QByteArray> roleNames() const override;
+
+ int count() const;
+ Q_INVOKABLE QVariantMap get(int index) const;
+ Q_INVOKABLE Package *package(int index) const;
+ Q_INVOKABLE Package *package(const QString &id) const;
+ Q_INVOKABLE int indexOfPackage(const QString &id) const;
+
+ bool developmentMode() const;
+ void setDevelopmentMode(bool enable);
+ bool allowInstallationOfUnsignedPackages() const;
+ void setAllowInstallationOfUnsignedPackages(bool enable);
+ QString hardwareId() const;
+ void setHardwareId(const QString &hwId);
+// bool securityChecksEnabled() const;
+// void setSecurityChecksEnabled(bool enabled);
+
+ bool isApplicationUserIdSeparationEnabled() const;
+ uint commonApplicationGroupId() const;
+
+ bool enableApplicationUserIdSeparation(uint minUserId, uint maxUserId, uint commonGroupId);
+
+ void setCACertificates(const QList<QByteArray> &chainOfTrust);
+
+ void cleanupBrokenInstallations() Q_DECL_NOEXCEPT_EXPR(false);
+
+ QVariantMap installationLocation() const;
+ QVariantMap documentLocation() const;
+
+ // Q_SCRIPTABLEs are available via both QML and D-Bus
+ Q_SCRIPTABLE QStringList packageIds() const;
+ Q_SCRIPTABLE QVariantMap get(const QString &id) const;
+
+ Q_SCRIPTABLE qint64 installedPackageSize(const QString &packageId) const;
+ Q_SCRIPTABLE QVariantMap installedPackageExtraMetaData(const QString &packageId) const;
+ Q_SCRIPTABLE QVariantMap installedPackageExtraSignedMetaData(const QString &packageId) const;
+
+ // all QString return values are task-ids
+ QString startPackageInstallation(const QUrl &sourceUrl);
+ Q_SCRIPTABLE QString startPackageInstallation(const QString &sourceUrl);
+ Q_SCRIPTABLE void acknowledgePackageInstallation(const QString &taskId);
+ Q_SCRIPTABLE QString removePackage(const QString &id, bool keepDocuments, bool force = false);
+
+ Q_SCRIPTABLE AsynchronousTask::TaskState taskState(const QString &taskId) const;
+ Q_SCRIPTABLE QString taskPackageId(const QString &taskId) const;
+ Q_SCRIPTABLE QStringList activeTaskIds() const;
+ Q_SCRIPTABLE bool cancelTask(const QString &taskId);
+
+ // convenience function for app-store implementations
+ Q_SCRIPTABLE int compareVersions(const QString &version1, const QString &version2);
+ Q_SCRIPTABLE bool validateDnsName(const QString &name, int minimumParts = 1);
+
+ PackageManagerInternalSignals internalSignals;
+
+signals:
+ Q_SCRIPTABLE void countChanged();
+
+ Q_SCRIPTABLE void packageAdded(const QString &id);
+ Q_SCRIPTABLE void packageAboutToBeRemoved(const QString &id);
+ Q_SCRIPTABLE void packageChanged(const QString &id, const QStringList &changedRoles);
+
+ Q_SCRIPTABLE void taskStarted(const QString &taskId);
+ Q_SCRIPTABLE void taskProgressChanged(const QString &taskId, qreal progress);
+ Q_SCRIPTABLE void taskFinished(const QString &taskId);
+ Q_SCRIPTABLE void taskFailed(const QString &taskId, int errorCode, const QString &errorString);
+ Q_SCRIPTABLE void taskStateChanged(const QString &taskId,
+ QT_PREPEND_NAMESPACE_AM(AsynchronousTask::TaskState) newState);
+
+ // installation only
+ Q_SCRIPTABLE void taskRequestingInstallationAcknowledge(const QString &taskId,
+ const QVariantMap &packageAsVariantMap,
+ const QVariantMap &packageExtraMetaData,
+ const QVariantMap &packageExtraSignedMetaData);
+ Q_SCRIPTABLE void taskBlockingUntilInstallationAcknowledge(const QString &taskId);
+
+private slots:
+ void executeNextTask();
+
+protected:
+ bool startingPackageInstallation(PackageInfo *info);
+ bool startingPackageRemoval(const QString &id);
+ bool finishedPackageInstall(const QString &id);
+ bool canceledPackageInstall(const QString &id);
+
+private:
+ void emitDataChanged(Package *package, const QVector<int> &roles = QVector<int>());
+ void registerPackage(PackageInfo *packageInfo, PackageInfo *updatedPackageInfo,
+ bool currentlyBeingInstalled = false);
+ void registerApplicationsAndIntentsOfPackage(Package *package);
+ void unregisterApplicationsAndIntentsOfPackage(Package *package);
+ static void registerQmlTypes();
+
+ void triggerExecuteNextTask();
+ QString enqueueTask(AsynchronousTask *task);
+ void handleFailure(AsynchronousTask *task);
+
+ QList<QByteArray> caCertificates() const;
+
+private:
+ uint findUnusedUserId() const Q_DECL_NOEXCEPT_EXPR(false);
+
+ explicit PackageManager(PackageDatabase *packageDatabase,
+ const QString &documentPath);
+ PackageManager(const PackageManager &);
+ PackageManager &operator=(const PackageManager &);
+ static PackageManager *s_instance;
+ static QHash<int, QByteArray> s_roleNames;
+
+ PackageManagerPrivate *d;
+
+ friend class InstallationTask;
+ friend class DeinstallationTask;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/installer-lib/applicationinstaller_p.h b/src/manager-lib/packagemanager_p.h
index 09fc1324..b841a3c1 100644
--- a/src/installer-lib/applicationinstaller_p.h
+++ b/src/manager-lib/packagemanager_p.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -48,17 +49,23 @@
#include <QScopedPointer>
#include <QThread>
-#include <QtAppManInstaller/applicationinstaller.h>
-#include <QtAppManInstaller/sudo.h>
+#include <QtAppManManager/packagemanager.h>
+#include <QtAppManApplication/packagedatabase.h>
+#include <QtAppManManager/asynchronoustask.h>
#include <QtAppManCommon/global.h>
QT_BEGIN_NAMESPACE_AM
bool removeRecursiveHelper(const QString &path);
-class ApplicationInstallerPrivate
+class PackageManagerPrivate
{
public:
+ PackageDatabase *database = nullptr;
+ QVector<Package *> packages;
+
+ QMap<Package *, PackageInfo *> pendingPackageInfoUpdates;
+
bool developmentMode = false;
bool allowInstallationOfUnsignedPackages = false;
bool userIdSeparation = false;
@@ -66,9 +73,8 @@ public:
uint maxUserId = uint(-1);
uint commonGroupId = uint(-1);
- QScopedPointer<QDir> manifestDir;
- QVector<InstallationLocation> installationLocations;
- InstallationLocation invalidInstallationLocation;
+ QString installationPath;
+ QString documentPath;
QString error;
diff --git a/src/manager-lib/plugincontainer.cpp b/src/manager-lib/plugincontainer.cpp
index 2150f8d4..32f334c0 100644
--- a/src/manager-lib/plugincontainer.cpp
+++ b/src/manager-lib/plugincontainer.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -61,7 +61,7 @@ bool PluginContainerManager::supportsQuickLaunch() const
return m_interface->supportsQuickLaunch();
}
-AbstractContainer *PluginContainerManager::create(AbstractApplication *app, const QVector<int> &stdioRedirections,
+AbstractContainer *PluginContainerManager::create(Application *app, const QVector<int> &stdioRedirections,
const QMap<QString, QString> &debugWrapperEnvironment,
const QStringList &debugWrapperCommand)
{
@@ -133,7 +133,7 @@ AbstractContainerProcess *PluginContainer::start(const QStringList &arguments, c
return nullptr;
}
-PluginContainer::PluginContainer(AbstractContainerManager *manager, AbstractApplication *app, ContainerInterface *containerInterface)
+PluginContainer::PluginContainer(AbstractContainerManager *manager, Application *app, ContainerInterface *containerInterface)
: AbstractContainer(manager, app)
, m_interface(containerInterface)
, m_process(new PluginContainerProcess(this))
diff --git a/src/manager-lib/plugincontainer.h b/src/manager-lib/plugincontainer.h
index acf250da..c97f2af2 100644
--- a/src/manager-lib/plugincontainer.h
+++ b/src/manager-lib/plugincontainer.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -56,7 +56,7 @@ public:
static QString defaultIdentifier();
bool supportsQuickLaunch() const override;
- AbstractContainer *create(AbstractApplication *app, const QVector<int> &stdioRedirections,
+ AbstractContainer *create(Application *app, const QVector<int> &stdioRedirections,
const QMap<QString, QString> &debugWrapperEnvironment,
const QStringList &debugWrapperCommand) override;
@@ -108,7 +108,7 @@ public:
const QVariantMap &amConfig) override;
protected:
- explicit PluginContainer(AbstractContainerManager *manager, AbstractApplication *app, ContainerInterface *containerInterface);
+ explicit PluginContainer(AbstractContainerManager *manager, Application *app, ContainerInterface *containerInterface);
ContainerInterface *m_interface;
PluginContainerProcess *m_process;
bool m_startCalled = false;
diff --git a/src/manager-lib/processcontainer.cpp b/src/manager-lib/processcontainer.cpp
index 23113239..57420100 100644
--- a/src/manager-lib/processcontainer.cpp
+++ b/src/manager-lib/processcontainer.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -183,7 +183,7 @@ void HostProcess::setStopBeforeExec(bool stopBeforeExec)
}
-ProcessContainer::ProcessContainer(ProcessContainerManager *manager, AbstractApplication *app,
+ProcessContainer::ProcessContainer(ProcessContainerManager *manager, Application *app,
const QVector<int> &stdioRedirections,
const QMap<QString, QString> &debugWrapperEnvironment,
const QStringList &debugWrapperCommand)
@@ -323,7 +323,7 @@ bool ProcessContainerManager::supportsQuickLaunch() const
return true;
}
-AbstractContainer *ProcessContainerManager::create(AbstractApplication *app, const QVector<int> &stdioRedirections,
+AbstractContainer *ProcessContainerManager::create(Application *app, const QVector<int> &stdioRedirections,
const QMap<QString, QString> &debugWrapperEnvironment,
const QStringList &debugWrapperCommand)
{
diff --git a/src/manager-lib/processcontainer.h b/src/manager-lib/processcontainer.h
index 65d11acb..99348a25 100644
--- a/src/manager-lib/processcontainer.h
+++ b/src/manager-lib/processcontainer.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -60,7 +60,7 @@ public:
static QString defaultIdentifier();
bool supportsQuickLaunch() const override;
- AbstractContainer *create(AbstractApplication *app, const QVector<int> &stdioRedirections,
+ AbstractContainer *create(Application *app, const QVector<int> &stdioRedirections,
const QMap<QString, QString> &debugWrapperEnvironment,
const QStringList &debugWrapperCommand) override;
};
@@ -100,7 +100,7 @@ class ProcessContainer : public AbstractContainer
Q_OBJECT
public:
- explicit ProcessContainer(ProcessContainerManager *manager, AbstractApplication *app,
+ explicit ProcessContainer(ProcessContainerManager *manager, Application *app,
const QVector<int> &stdioRedirections,
const QMap<QString, QString> &debugWrapperEnvironment,
const QStringList &debugWrapperCommand);
diff --git a/src/manager-lib/processstatus.cpp b/src/manager-lib/processstatus.cpp
index bc05f834..3f1ee50c 100644
--- a/src/manager-lib/processstatus.cpp
+++ b/src/manager-lib/processstatus.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -218,7 +218,7 @@ void ProcessStatus::setApplicationId(const QString &appId)
qmlWarning(this) << "Invalid application ID:" << appId;
} else {
m_application = ApplicationManager::instance()->application(appIndex);
- connect(m_application.data(), &AbstractApplication::runStateChanged, this, &ProcessStatus::onRunStateChanged);
+ connect(m_application.data(), &Application::runStateChanged, this, &ProcessStatus::onRunStateChanged);
}
}
determinePid();
diff --git a/src/manager-lib/processstatus.h b/src/manager-lib/processstatus.h
index 282ad13f..839f1d65 100644
--- a/src/manager-lib/processstatus.h
+++ b/src/manager-lib/processstatus.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -113,7 +113,7 @@ private:
QVariantMap m_memoryPss;
bool m_memoryReportingEnabled = true;
- QPointer<AbstractApplication> m_application;
+ QPointer<Application> m_application;
bool m_pendingUpdate = false;
ProcessReader *m_reader;
diff --git a/src/manager-lib/qmlinprocessapplicationinterface.cpp b/src/manager-lib/qmlinprocessapplicationinterface.cpp
index a24651b4..caceabe3 100644
--- a/src/manager-lib/qmlinprocessapplicationinterface.cpp
+++ b/src/manager-lib/qmlinprocessapplicationinterface.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -78,7 +78,7 @@ QVariantMap QmlInProcessApplicationInterface::name() const
{
QVariantMap names;
if (m_runtime && m_runtime->application()) {
- const QMap<QString, QString> &sm = m_runtime->application()->info()->names();
+ const QMap<QString, QString> &sm = m_runtime->application()->packageInfo()->names();
for (auto it = sm.cbegin(); it != sm.cend(); ++it)
names.insert(it.key(), it.value());
}
@@ -88,7 +88,7 @@ QVariantMap QmlInProcessApplicationInterface::name() const
QUrl QmlInProcessApplicationInterface::icon() const
{
if (m_runtime && m_runtime->application())
- return m_runtime->application()->icon();
+ return m_runtime->application()->packageInfo()->icon();
return QUrl();
}
diff --git a/src/manager-lib/qmlinprocessapplicationinterface.h b/src/manager-lib/qmlinprocessapplicationinterface.h
index 87b43bf7..669b1461 100644
--- a/src/manager-lib/qmlinprocessapplicationinterface.h
+++ b/src/manager-lib/qmlinprocessapplicationinterface.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/qmlinprocessapplicationmanagerwindow.cpp b/src/manager-lib/qmlinprocessapplicationmanagerwindow.cpp
index 8bf809aa..fe368b41 100644
--- a/src/manager-lib/qmlinprocessapplicationmanagerwindow.cpp
+++ b/src/manager-lib/qmlinprocessapplicationmanagerwindow.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -182,8 +182,6 @@ void QmlInProcessApplicationManagerWindow::data_clear(QQmlListProperty<QObject>
void QmlInProcessApplicationManagerWindow::componentComplete()
{
- qCDebug(LogSystem) << "QmlInProcessApplicationManagerWindow componentComplete() this:" << this;
-
if (!m_runtime)
m_runtime = QmlInProcessRuntime::determineRuntime(this);
diff --git a/src/manager-lib/qmlinprocessapplicationmanagerwindow.h b/src/manager-lib/qmlinprocessapplicationmanagerwindow.h
index 5207e3d4..55796cba 100644
--- a/src/manager-lib/qmlinprocessapplicationmanagerwindow.h
+++ b/src/manager-lib/qmlinprocessapplicationmanagerwindow.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/qmlinprocessruntime.cpp b/src/manager-lib/qmlinprocessruntime.cpp
index 099d0a64..f99529ab 100644
--- a/src/manager-lib/qmlinprocessruntime.cpp
+++ b/src/manager-lib/qmlinprocessruntime.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -105,9 +105,23 @@ bool QmlInProcessRuntime::start()
return false;
}
+ const QString codeDir = m_app->codeDir() + QDir::separator();
+
+ const QStringList resources = variantToStringList(configuration().value(qSL("resources")))
+ + variantToStringList(m_app->runtimeParameters().value(qSL("resources")));
+ for (const QString &resource : resources) {
+ const QString path = QFileInfo(resource).isRelative() ? codeDir + resource : resource;
+ static QStringList cache;
+ if (!cache.contains(path)) {
+ if (!loadResource(path))
+ qCWarning(LogQmlRuntime) << "Cannot register resource:" << path;
+ cache.append(path);
+ }
+ }
+
if (m_app->runtimeParameters().value(qSL("loadDummyData")).toBool()) {
qCDebug(LogSystem) << "Loading dummy-data";
- loadQmlDummyDataFiles(m_inProcessQmlEngine, QFileInfo(m_app->nonAliasedInfo()->absoluteCodeFilePath()).path());
+ loadQmlDummyDataFiles(m_inProcessQmlEngine, QFileInfo(m_app->info()->absoluteCodeFilePath()).path());
}
const QStringList pluginPaths = variantToStringList(configuration().value(qSL("pluginPaths")))
@@ -124,18 +138,17 @@ bool QmlInProcessRuntime::start()
const QStringList importPaths = variantToStringList(configuration().value(qSL("importPaths")))
+ variantToStringList(m_app->runtimeParameters().value(qSL("importPaths")));
if (!importPaths.isEmpty()) {
- const QString codeDir = m_app->codeDir() + QDir::separator();
for (const QString &path : importPaths)
- m_inProcessQmlEngine->addImportPath(QFileInfo(path).isRelative() ? codeDir + path : path);
+ m_inProcessQmlEngine->addImportPath(toAbsoluteFilePath(path, codeDir));
qCDebug(LogSystem) << "Updated Qml import paths:" << m_inProcessQmlEngine->importPathList();
}
- m_componentError = false;
- QQmlComponent *component = new QQmlComponent(m_inProcessQmlEngine, m_app->nonAliasedInfo()->absoluteCodeFilePath());
+ const QUrl qmlFileUrl = filePathToUrl(m_app->info()->absoluteCodeFilePath(), codeDir);
+ QQmlComponent *component = new QQmlComponent(m_inProcessQmlEngine, qmlFileUrl);
if (!component->isReady()) {
- qCDebug(LogSystem) << "qml-file (" << m_app->nonAliasedInfo()->absoluteCodeFilePath() << "): component not ready:\n" << component->errorString();
+ qCDebug(LogSystem) << "qml-file (" << m_app->info()->absoluteCodeFilePath() << "): component not ready:\n" << component->errorString();
return false;
}
@@ -154,8 +167,8 @@ bool QmlInProcessRuntime::start()
QMetaObject::invokeMethod(this, [component, appContext, obj, this]() {
component->completeCreate();
- if (!obj || m_componentError) {
- qCCritical(LogSystem) << "could not load" << m_app->nonAliasedInfo()->absoluteCodeFilePath() << ": no root object";
+ if (!obj) {
+ qCCritical(LogSystem) << "could not load" << m_app->info()->absoluteCodeFilePath() << ": no root object";
delete obj;
delete appContext;
delete m_applicationIf;
@@ -203,7 +216,7 @@ void QmlInProcessRuntime::stop(bool forceKill)
#else
int exitCode = 0;
#endif
- finish(exitCode, Am::CrashExit);
+ finish(exitCode, Am::ForcedExit);
return;
}
@@ -217,7 +230,7 @@ void QmlInProcessRuntime::stop(bool forceKill)
#else
int exitCode = 0;
#endif
- finish(exitCode, Am::CrashExit);
+ finish(exitCode, Am::ForcedExit);
});
}
diff --git a/src/manager-lib/qmlinprocessruntime.h b/src/manager-lib/qmlinprocessruntime.h
index f2d57eb6..0efc7495 100644
--- a/src/manager-lib/qmlinprocessruntime.h
+++ b/src/manager-lib/qmlinprocessruntime.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -100,7 +100,6 @@ private:
QString m_document;
QmlInProcessApplicationInterface *m_applicationIf = nullptr;
- bool m_componentError;
bool m_stopIfNoVisibleSurfaces = false;
diff --git a/src/manager-lib/quicklauncher.cpp b/src/manager-lib/quicklauncher.cpp
index 2cf841d5..2494b840 100644
--- a/src/manager-lib/quicklauncher.cpp
+++ b/src/manager-lib/quicklauncher.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/quicklauncher.h b/src/manager-lib/quicklauncher.h
index c1a0cb94..8fd74e8c 100644
--- a/src/manager-lib/quicklauncher.h
+++ b/src/manager-lib/quicklauncher.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/runtimefactory.cpp b/src/manager-lib/runtimefactory.cpp
index c87561ea..bf00c31a 100644
--- a/src/manager-lib/runtimefactory.cpp
+++ b/src/manager-lib/runtimefactory.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/manager-lib/runtimefactory.h b/src/manager-lib/runtimefactory.h
index 7e41a4d4..66e0222a 100644
--- a/src/manager-lib/runtimefactory.h
+++ b/src/manager-lib/runtimefactory.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/installer-lib/scopeutilities.cpp b/src/manager-lib/scopeutilities.cpp
index 45fe4742..089e03cf 100644
--- a/src/installer-lib/scopeutilities.cpp
+++ b/src/manager-lib/scopeutilities.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -42,7 +42,7 @@
#include "logging.h"
#include "scopeutilities.h"
-#include "applicationinstaller_p.h"
+#include "packagemanager_p.h"
#include "utilities.h"
QT_BEGIN_NAMESPACE_AM
@@ -92,7 +92,6 @@ QDir ScopedDirectoryCreator::dir()
return QDir(m_path);
}
-
ScopedRenamer::ScopedRenamer()
{ }
diff --git a/src/installer-lib/scopeutilities.h b/src/manager-lib/scopeutilities.h
index f3d30424..7ebe5166 100644
--- a/src/installer-lib/scopeutilities.h
+++ b/src/manager-lib/scopeutilities.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/installer-lib/sudo.cpp b/src/manager-lib/sudo.cpp
index b7e5578b..729c4665 100644
--- a/src/installer-lib/sudo.cpp
+++ b/src/manager-lib/sudo.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/installer-lib/sudo.h b/src/manager-lib/sudo.h
index 357261e6..33215279 100644
--- a/src/installer-lib/sudo.h
+++ b/src/manager-lib/sudo.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/monitor-lib/processreader.cpp b/src/monitor-lib/processreader.cpp
index e8b760a9..30ca5c38 100644
--- a/src/monitor-lib/processreader.cpp
+++ b/src/monitor-lib/processreader.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -347,7 +347,8 @@ bool ProcessReader::readMemory()
struct task_basic_info t_info;
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
- if (KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count)) {
+ if (KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO,
+ reinterpret_cast<task_info_t>(&t_info), &t_info_count)) {
qCWarning(LogSystem) << "Could not read memory data";
return false;
}
diff --git a/src/monitor-lib/processreader.h b/src/monitor-lib/processreader.h
index 9d63790f..a6c6bc35 100644
--- a/src/monitor-lib/processreader.h
+++ b/src/monitor-lib/processreader.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/monitor-lib/sysfsreader.cpp b/src/monitor-lib/sysfsreader.cpp
index d100dc43..3465b623 100644
--- a/src/monitor-lib/sysfsreader.cpp
+++ b/src/monitor-lib/sysfsreader.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -44,7 +44,7 @@
#include <qplatformdefs.h>
#include "sysfsreader.h"
-# define EINTR_LOOP(cmd) __extension__ ({__typeof__(cmd) res = 0; do { res = cmd; } while (res == -1 && errno == EINTR); res; })
+#define EINTR_LOOP(cmd) __extension__ ({__typeof__(cmd) res = 0; do { res = cmd; } while (res == -1 && errno == EINTR); res; })
static inline int qt_safe_open(const char *pathname, int flags, mode_t mode = 0777)
{
@@ -56,8 +56,9 @@ static inline int qt_safe_open(const char *pathname, int flags, mode_t mode = 07
::fcntl(fd, F_SETFD, FD_CLOEXEC);
return fd;
}
-# undef QT_OPEN
-# define QT_OPEN qt_safe_open
+
+#undef QT_OPEN
+#define QT_OPEN qt_safe_open
QT_BEGIN_NAMESPACE_AM
@@ -94,7 +95,7 @@ QByteArray SysFsReader::readValue() const
int offset = 0;
int read = 0;
do {
- read = static_cast<int>(EINTR_LOOP(QT_READ(m_fd, m_buffer.data() + offset, m_buffer.size() - offset)));
+ read = int(EINTR_LOOP(QT_READ(m_fd, m_buffer.data() + offset, size_t(m_buffer.size() - offset))));
if (read < 0)
return QByteArray();
else if (read < (m_buffer.size() - offset))
diff --git a/src/monitor-lib/sysfsreader.h b/src/monitor-lib/sysfsreader.h
index 8a299177..127ddb2f 100644
--- a/src/monitor-lib/sysfsreader.h
+++ b/src/monitor-lib/sysfsreader.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/monitor-lib/systemreader.cpp b/src/monitor-lib/systemreader.cpp
index 67692fe1..3feaa813 100644
--- a/src/monitor-lib/systemreader.cpp
+++ b/src/monitor-lib/systemreader.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -686,8 +686,9 @@ qreal CpuReader::readLoadValue()
mach_msg_type_number_t cpuLoadInfoCount = 0;
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpuCount,
- (processor_info_array_t *) &cpuLoadInfo, &cpuLoadInfoCount) == KERN_SUCCESS) {
- uint64_t idle = 0, total = 0;
+ reinterpret_cast<processor_info_array_t *>(&cpuLoadInfo),
+ &cpuLoadInfoCount) == KERN_SUCCESS) {
+ qint64 idle = 0, total = 0;
for (natural_t i = 0; i < cpuCount; ++i) {
idle += cpuLoadInfo[i].cpu_ticks[CPU_STATE_IDLE];
@@ -696,7 +697,7 @@ qreal CpuReader::readLoadValue()
+ cpuLoadInfo[i].cpu_ticks[CPU_STATE_IDLE] \
+ cpuLoadInfo[i].cpu_ticks[CPU_STATE_NICE];
}
- vm_deallocate(mach_task_self(), (vm_address_t) cpuLoadInfo, cpuLoadInfoCount);
+ vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(cpuLoadInfo), cpuLoadInfoCount);
m_load = qreal(1) - (qreal(idle - m_lastIdle) / qreal(total - m_lastTotal));
@@ -719,7 +720,7 @@ MemoryReader::MemoryReader()
size_t hwMemSize = sizeof(hwMem);
if (sysctl(mib, sizeof(mib) / sizeof(*mib), &hwMem, &hwMemSize, nullptr, 0) == KERN_SUCCESS)
- s_totalValue = hwMem;
+ s_totalValue = quint64(hwMem);
mib[1] = HW_PAGESIZE;
int hwPageSize;
@@ -735,12 +736,13 @@ quint64 MemoryReader::readUsedValue() const
vm_statistics64_data_t vmStat;
mach_msg_type_number_t vmStatCount = HOST_VM_INFO64_COUNT;
- if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t) &vmStat, &vmStatCount) == KERN_SUCCESS) {
+ if (host_statistics64(mach_host_self(), HOST_VM_INFO64,
+ reinterpret_cast<host_info64_t>(&vmStat), &vmStatCount) == KERN_SUCCESS) {
quint64 app = vmStat.internal_page_count;
quint64 compressed = vmStat.compressor_page_count;
quint64 wired = vmStat.wire_count;
- return (app + compressed + wired) * s_pageSize;
+ return (app + compressed + wired) * quint64(s_pageSize);
} else {
return 0;
}
diff --git a/src/monitor-lib/systemreader.h b/src/monitor-lib/systemreader.h
index a6879495..df5c48fa 100644
--- a/src/monitor-lib/systemreader.h
+++ b/src/monitor-lib/systemreader.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/notification-lib/notification.cpp b/src/notification-lib/notification.cpp
index 0df9055f..588513a0 100644
--- a/src/notification-lib/notification.cpp
+++ b/src/notification-lib/notification.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/notification-lib/notification.h b/src/notification-lib/notification.h
index 5dfcfd81..d4ecc501 100644
--- a/src/notification-lib/notification.h
+++ b/src/notification-lib/notification.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/package-lib/package-lib.pro b/src/package-lib/package-lib.pro
index d38aa343..056649c2 100644
--- a/src/package-lib/package-lib.pro
+++ b/src/package-lib/package-lib.pro
@@ -17,17 +17,16 @@ include($$SOURCE_DIR/3rdparty/libarchive.pri)
include($$SOURCE_DIR/3rdparty/libz.pri)
HEADERS += \
- package_p.h \
packageextractor_p.h \
packageextractor.h \
packagecreator_p.h \
packagecreator.h \
- package.h
+ packageutilities.h \
+ packageutilities_p.h \
SOURCES += \
- package_p.cpp \
packagecreator.cpp \
packageextractor.cpp \
- package.cpp
+ packageutilities.cpp
load(qt_module)
diff --git a/src/package-lib/package_p.cpp b/src/package-lib/package_p.cpp
deleted file mode 100644
index 702b94a2..00000000
--- a/src/package-lib/package_p.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Luxoft Sweden AB
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Luxoft Application Manager.
-**
-** $QT_BEGIN_LICENSE:LGPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** 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-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: LGPL-3.0
-**
-****************************************************************************/
-
-
-#include <QFileInfo>
-#include <QDataStream>
-#include <QCryptographicHash>
-
-#include <archive.h>
-
-#include "package_p.h"
-
-QT_BEGIN_NAMESPACE_AM
-
-ArchiveException::ArchiveException(struct ::archive *ar, const char *errorString)
- : Exception(Error::Archive, qSL("[libarchive] ") + qL1S(errorString) + qSL(": ") + QString::fromLocal8Bit(::archive_error_string(ar)))
-{ }
-
-
-QVariantMap PackageUtilities::headerDataForDigest = QVariantMap {
- { "extraSigned", QVariantMap() }
-};
-
-void PackageUtilities::addFileMetadataToDigest(const QString &entryFilePath, const QFileInfo &fi, QCryptographicHash &digest)
-{
- // (using QDataStream would be more readable, but it would make the algorithm Qt dependent)
- QByteArray addToDigest = ((fi.isDir()) ? "D/" : "F/")
- + QByteArray::number(fi.isDir() ? 0 : fi.size())
- + '/' + entryFilePath.toUtf8();
- digest.addData(addToDigest);
-}
-
-void PackageUtilities::addHeaderDataToDigest(const QVariantMap &header, QCryptographicHash &digest) Q_DECL_NOEXCEPT_EXPR(false)
-{
- for (auto it = headerDataForDigest.constBegin(); it != headerDataForDigest.constEnd(); ++it) {
- if (header.contains(it.key())) {
- QByteArray ba;
- QDataStream ds(&ba, QIODevice::WriteOnly);
-
- QVariant v = header.value(it.key());
- if (!v.convert(int(it.value().type())))
- throw Exception(Error::Package, "metadata field %1 has invalid type for digest calculation (cannot convert %2 to %3)")
- .arg(it.key()).arg(header.value(it.key()).type()).arg(it.value().type());
- ds << v;
-
- digest.addData(ba);
- }
- }
-}
-
-QT_END_NAMESPACE_AM
diff --git a/src/package-lib/packagecreator.cpp b/src/package-lib/packagecreator.cpp
index fcfa5c85..4a4f50c8 100644
--- a/src/package-lib/packagecreator.cpp
+++ b/src/package-lib/packagecreator.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -51,7 +51,7 @@
#include <archive.h>
#include <archive_entry.h>
-#include "package_p.h"
+#include "packageutilities_p.h"
#include "packagecreator.h"
#include "packagecreator_p.h"
#include "exception.h"
@@ -81,7 +81,7 @@ QT_BEGIN_NAMESPACE_AM
*/
static void fixed_archive_entry_set_pathname(archive_entry *entry, const QString &pathname)
{
- wchar_t *wchars = new wchar_t[pathname.length() + 1];
+ wchar_t *wchars = new wchar_t[size_t(pathname.length()) + 1];
wchars[pathname.toWCharArray(wchars)] = 0;
archive_entry_copy_pathname_w(entry, wchars);
delete[] wchars;
@@ -174,18 +174,18 @@ bool PackageCreatorPrivate::create()
char buffer[64 * 1024];
try {
- if (m_report.applicationId().isNull())
+ if (m_report.packageId().isNull())
throw Exception("package identifier is null");
QCryptographicHash digest(QCryptographicHash::Sha256);
QVariantMap headerFormat {
{ qSL("formatType"), qSL("am-package-header") },
- { qSL("formatVersion"), 1 }
+ { qSL("formatVersion"), 2 }
};
m_metaData = QVariantMap {
- { qSL("applicationId"), m_report.applicationId() },
+ { qSL("packageId"), m_report.packageId() },
{ qSL("diskSpaceUsed"), m_report.diskSpaceUsed() }
};
if (!m_report.extraMetaData().isEmpty())
@@ -342,7 +342,7 @@ bool PackageCreatorPrivate::create()
QVariantMap footerFormat {
{ qSL("formatType"), qSL("am-package-footer") },
- { qSL("formatVersion"), 1 }
+ { qSL("formatVersion"), 2 }
};
QVariantMap footerData {
diff --git a/src/package-lib/packagecreator.h b/src/package-lib/packagecreator.h
index 34044760..b3021dce 100644
--- a/src/package-lib/packagecreator.h
+++ b/src/package-lib/packagecreator.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/package-lib/packagecreator_p.h b/src/package-lib/packagecreator_p.h
index 47016af4..4175559f 100644
--- a/src/package-lib/packagecreator_p.h
+++ b/src/package-lib/packagecreator_p.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/package-lib/packageextractor.cpp b/src/package-lib/packageextractor.cpp
index 6ecdff0e..c3244c6f 100644
--- a/src/package-lib/packageextractor.cpp
+++ b/src/package-lib/packageextractor.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -54,14 +55,14 @@
#include <archive.h>
#include <archive_entry.h>
-#include "package_p.h"
+#include "packageutilities_p.h"
#include "packageextractor.h"
#include "packageextractor_p.h"
#include "exception.h"
#include "error.h"
#include "installationreport.h"
#include "utilities.h"
-#include "applicationinfo.h"
+#include "packageinfo.h"
#include "qtyaml.h"
// archive.h might #define this for Android
@@ -455,15 +456,17 @@ void PackageExtractorPrivate::extract()
void PackageExtractorPrivate::processMetaData(const QByteArray &metadata, QCryptographicHash &digest,
bool isHeader) Q_DECL_NOEXCEPT_EXPR(false)
{
- QtYaml::ParseError error;
- QVector<QVariant> docs = QtYaml::variantDocumentsFromYaml(metadata, &error);
-
- if (error.error != QJsonParseError::NoError)
- throw Exception(Error::Package, "metadata is not a valid YAML document: %1 (line: %2, column %3)")
- .arg(error.errorString()).arg(error.line).arg(error.column);
+ QVector<QVariant> docs;
+ try {
+ docs = YamlParser::parseAllDocuments(metadata);
+ } catch (const Exception &e) {
+ throw Exception(Error::Package, "metadata is not a valid YAML document: %1")
+ .arg(e.errorString());
+ }
try {
- checkYamlFormat(docs, -2 /*at least 2 docs*/, { isHeader ? "am-package-header" : "am-package-footer" }, 1);
+ checkYamlFormat(docs, -2 /*at least 2 docs*/, { { isHeader ? qSL("am-package-header")
+ : qSL("am-package-footer"), 2 } });
} catch (const Exception &e) {
throw Exception(Error::Package, "metadata has an invalid format specification: %1").arg(e.errorString());
}
@@ -471,12 +474,12 @@ void PackageExtractorPrivate::processMetaData(const QByteArray &metadata, QCrypt
QVariantMap map = docs.at(1).toMap();
if (isHeader) {
- QString applicationId = map.value(qSL("applicationId")).toString();
+ QString packageId = map.value(qSL("packageId")).toString();
quint64 diskSpaceUsed = map.value(qSL("diskSpaceUsed")).toULongLong();
- if (applicationId.isNull() || !ApplicationInfo::isValidApplicationId(applicationId))
- throw Exception(Error::Package, "metadata has an invalid applicationId field (%1)").arg(applicationId);
- m_report.setApplicationId(applicationId);
+ if (packageId.isNull() || !PackageInfo::isValidApplicationId(packageId))
+ throw Exception(Error::Package, "metadata has an invalid packageId field (%1)").arg(packageId);
+ m_report.setPackageId(packageId);
if (!diskSpaceUsed)
throw Exception(Error::Package, "metadata has an invalid diskSpaceUsed field (%1)").arg(diskSpaceUsed);
diff --git a/src/package-lib/packageextractor.h b/src/package-lib/packageextractor.h
index eb3b1e7f..13b92871 100644
--- a/src/package-lib/packageextractor.h
+++ b/src/package-lib/packageextractor.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/package-lib/packageextractor_p.h b/src/package-lib/packageextractor_p.h
index a8f72c8a..5463fcf5 100644
--- a/src/package-lib/packageextractor_p.h
+++ b/src/package-lib/packageextractor_p.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/package-lib/package.cpp b/src/package-lib/packageutilities.cpp
index 481117e9..f5e80180 100644
--- a/src/package-lib/package.cpp
+++ b/src/package-lib/packageutilities.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -40,17 +40,25 @@
**
****************************************************************************/
+
+#include <QFileInfo>
+#include <QDataStream>
+#include <QCryptographicHash>
#include <QByteArray>
#include <QString>
-#include "package.h"
+#include <archive.h>
+
+#include "packageutilities.h"
+#include "packageutilities_p.h"
#include "global.h"
#include <clocale>
+
QT_BEGIN_NAMESPACE_AM
-bool Package::ensureCorrectLocale(QStringList *warnings)
+bool PackageUtilities::ensureCorrectLocale(QStringList *warnings)
{
// We need to make sure we are running in a Unicode locale, since we are
// running into problems when unpacking packages with libarchive that
@@ -119,7 +127,7 @@ bool Package::ensureCorrectLocale(QStringList *warnings)
}
-bool Package::checkCorrectLocale()
+bool PackageUtilities::checkCorrectLocale()
{
// see ensureCorrectLocale() above. Call this after the QApplication
// constructor as a sanity check.
@@ -131,4 +139,41 @@ bool Package::checkCorrectLocale()
#endif
}
+
+ArchiveException::ArchiveException(struct ::archive *ar, const char *errorString)
+ : Exception(Error::Archive, qSL("[libarchive] ") + qL1S(errorString) + qSL(": ") + QString::fromLocal8Bit(::archive_error_string(ar)))
+{ }
+
+
+QVariantMap PackageUtilities::headerDataForDigest = QVariantMap {
+ { "extraSigned", QVariantMap() }
+};
+
+void PackageUtilities::addFileMetadataToDigest(const QString &entryFilePath, const QFileInfo &fi, QCryptographicHash &digest)
+{
+ // (using QDataStream would be more readable, but it would make the algorithm Qt dependent)
+ QByteArray addToDigest = ((fi.isDir()) ? "D/" : "F/")
+ + QByteArray::number(fi.isDir() ? 0 : fi.size())
+ + '/' + entryFilePath.toUtf8();
+ digest.addData(addToDigest);
+}
+
+void PackageUtilities::addHeaderDataToDigest(const QVariantMap &header, QCryptographicHash &digest) Q_DECL_NOEXCEPT_EXPR(false)
+{
+ for (auto it = headerDataForDigest.constBegin(); it != headerDataForDigest.constEnd(); ++it) {
+ if (header.contains(it.key())) {
+ QByteArray ba;
+ QDataStream ds(&ba, QIODevice::WriteOnly);
+
+ QVariant v = header.value(it.key());
+ if (!v.convert(int(it.value().type())))
+ throw Exception(Error::Package, "metadata field %1 has invalid type for digest calculation (cannot convert %2 to %3)")
+ .arg(it.key()).arg(header.value(it.key()).type()).arg(it.value().type());
+ ds << v;
+
+ digest.addData(ba);
+ }
+ }
+}
+
QT_END_NAMESPACE_AM
diff --git a/src/package-lib/package.h b/src/package-lib/packageutilities.h
index 44d0561a..2b9c4a8b 100644
--- a/src/package-lib/package.h
+++ b/src/package-lib/packageutilities.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -47,7 +47,7 @@
QT_BEGIN_NAMESPACE_AM
-namespace Package
+namespace PackageUtilities
{
bool ensureCorrectLocale(QStringList *warnings = nullptr);
bool checkCorrectLocale();
diff --git a/src/package-lib/package_p.h b/src/package-lib/packageutilities_p.h
index d1218fae..62e1a90a 100644
--- a/src/package-lib/package_p.h
+++ b/src/package-lib/packageutilities_p.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -52,14 +52,13 @@ QT_FORWARD_DECLARE_CLASS(QCryptographicHash)
QT_BEGIN_NAMESPACE_AM
-class PackageUtilities
+namespace PackageUtilities
{
-public:
- static void addFileMetadataToDigest(const QString &entryFilePath, const QFileInfo &fi, QCryptographicHash &digest);
- static void addHeaderDataToDigest(const QVariantMap &header, QCryptographicHash &digest) Q_DECL_NOEXCEPT_EXPR(false);
+void addFileMetadataToDigest(const QString &entryFilePath, const QFileInfo &fi, QCryptographicHash &digest);
+void addHeaderDataToDigest(const QVariantMap &header, QCryptographicHash &digest) Q_DECL_NOEXCEPT_EXPR(false);
- // key == field name, value == type to choose correct hashing algorithm
- static QVariantMap headerDataForDigest;
+// key == field name, value == type to choose correct hashing algorithm
+extern QVariantMap headerDataForDigest;
};
enum PackageEntryType {
diff --git a/src/plugin-interfaces/containerinterface.cpp b/src/plugin-interfaces/containerinterface.cpp
index 0415f5d8..58fc5228 100644
--- a/src/plugin-interfaces/containerinterface.cpp
+++ b/src/plugin-interfaces/containerinterface.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -131,10 +131,6 @@ ContainerManagerInterface::~ContainerManagerInterface() { }
\row
\li \c applicationProperties
\li A map with all application properties as seen in the manifest.
- \row
- \li \c installationLocationId
- \li The installation location id, if this application was installed - empty for built-in
- applications.
\endtable
*/
diff --git a/src/plugin-interfaces/containerinterface.h b/src/plugin-interfaces/containerinterface.h
index 010959c4..64b81a92 100644
--- a/src/plugin-interfaces/containerinterface.h
+++ b/src/plugin-interfaces/containerinterface.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/plugin-interfaces/startupinterface.cpp b/src/plugin-interfaces/startupinterface.cpp
index 07e27708..73db5db3 100644
--- a/src/plugin-interfaces/startupinterface.cpp
+++ b/src/plugin-interfaces/startupinterface.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/plugin-interfaces/startupinterface.h b/src/plugin-interfaces/startupinterface.h
index b0125784..a8b710fe 100644
--- a/src/plugin-interfaces/startupinterface.h
+++ b/src/plugin-interfaces/startupinterface.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/cpustatus.cpp b/src/shared-main-lib/cpustatus.cpp
index d192781d..b98891cc 100644
--- a/src/shared-main-lib/cpustatus.cpp
+++ b/src/shared-main-lib/cpustatus.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/cpustatus.h b/src/shared-main-lib/cpustatus.h
index f7e37867..30393fa6 100644
--- a/src/shared-main-lib/cpustatus.h
+++ b/src/shared-main-lib/cpustatus.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/frametimer.cpp b/src/shared-main-lib/frametimer.cpp
index 1805f0ee..7751599b 100644
--- a/src/shared-main-lib/frametimer.cpp
+++ b/src/shared-main-lib/frametimer.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/frametimer.h b/src/shared-main-lib/frametimer.h
index 384f9a09..30c5225d 100644
--- a/src/shared-main-lib/frametimer.h
+++ b/src/shared-main-lib/frametimer.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/gpustatus.cpp b/src/shared-main-lib/gpustatus.cpp
index efa7d2ad..69692ce8 100644
--- a/src/shared-main-lib/gpustatus.cpp
+++ b/src/shared-main-lib/gpustatus.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/gpustatus.h b/src/shared-main-lib/gpustatus.h
index e7e23f7c..2a0df87d 100644
--- a/src/shared-main-lib/gpustatus.h
+++ b/src/shared-main-lib/gpustatus.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/iostatus.cpp b/src/shared-main-lib/iostatus.cpp
index fba8fff6..8c771015 100644
--- a/src/shared-main-lib/iostatus.cpp
+++ b/src/shared-main-lib/iostatus.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/iostatus.h b/src/shared-main-lib/iostatus.h
index b6070fad..0c7f4c3f 100644
--- a/src/shared-main-lib/iostatus.h
+++ b/src/shared-main-lib/iostatus.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/memorystatus.cpp b/src/shared-main-lib/memorystatus.cpp
index 1b6909a7..730f5894 100644
--- a/src/shared-main-lib/memorystatus.cpp
+++ b/src/shared-main-lib/memorystatus.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/memorystatus.h b/src/shared-main-lib/memorystatus.h
index 716c9f82..d9dcc8da 100644
--- a/src/shared-main-lib/memorystatus.h
+++ b/src/shared-main-lib/memorystatus.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/monitormodel.cpp b/src/shared-main-lib/monitormodel.cpp
index 5dbda61d..1433b608 100644
--- a/src/shared-main-lib/monitormodel.cpp
+++ b/src/shared-main-lib/monitormodel.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/monitormodel.h b/src/shared-main-lib/monitormodel.h
index 5def27dd..b7d80e9a 100644
--- a/src/shared-main-lib/monitormodel.h
+++ b/src/shared-main-lib/monitormodel.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/qmllogger.cpp b/src/shared-main-lib/qmllogger.cpp
index 7ec4303c..b40bfc52 100644
--- a/src/shared-main-lib/qmllogger.cpp
+++ b/src/shared-main-lib/qmllogger.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/qmllogger.h b/src/shared-main-lib/qmllogger.h
index ab39412b..a47c31d3 100644
--- a/src/shared-main-lib/qmllogger.h
+++ b/src/shared-main-lib/qmllogger.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/shared-main-lib/sharedmain.cpp b/src/shared-main-lib/sharedmain.cpp
index 647eb91f..f34fcdea 100644
--- a/src/shared-main-lib/sharedmain.cpp
+++ b/src/shared-main-lib/sharedmain.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -84,21 +84,34 @@ static QMap<int, QString> openGLProfileNames = {
{ QSurfaceFormat::CoreProfile, qSL("core") },
{ QSurfaceFormat::CompatibilityProfile, qSL("compatibility") }
};
+
+bool QtAM::SharedMain::s_initialized = false;
#endif
SharedMain::SharedMain()
-{ }
+{
+#if !defined(AM_HEADLESS)
+ if (Q_UNLIKELY(!s_initialized || !QCoreApplication::instance())) {
+ qCritical() << "ERROR: Q(Gui)Application must be instantiated after SharedMain::initialize "
+ "has been called and before SharedMain is instantiated";
+ }
+#endif
+}
SharedMain::~SharedMain()
{
delete m_debuggingEnabler;
}
-// We need to do some things BEFORE the Q*Application constructor runs, so we're using this
-// old trick to do this hooking transparently for the user of the class.
-int &SharedMain::preConstructor(int &argc)
+// Initialization routine that needs to be called BEFORE the Q*Application constructor
+void SharedMain::initialize()
{
#if !defined(AM_HEADLESS)
+ if (Q_UNLIKELY(QCoreApplication::instance()))
+ qCritical() << "ERROR: SharedMain::initialize must be called before Q(Gui)Application is instantiated.";
+
+ s_initialized = true;
+
# if !defined(QT_NO_SESSIONMANAGER)
QGuiApplication::setFallbackSessionManagementEnabled(false);
# endif
@@ -118,6 +131,13 @@ int &SharedMain::preConstructor(int &argc)
setenv("XDG_RUNTIME_DIR", QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation).toLocal8Bit(), 1);
# endif
#endif
+}
+
+// We need to do some things BEFORE the Q*Application constructor runs, so we're using this
+// old trick to do this hooking transparently for the user of the class.
+int &SharedMain::preConstructor(int &argc)
+{
+ initialize();
return argc;
}
@@ -134,23 +154,26 @@ void SharedMain::setupIconTheme(const QStringList &themeSearchPaths, const QStri
void SharedMain::setupQmlDebugging(bool qmlDebugging)
{
- bool hasJSDebugArg = !static_cast<QCoreApplicationPrivate *>(QObjectPrivate::get(qApp))->qmljsDebugArgumentsString().isEmpty();
+ bool hasJSDebugArg = !static_cast<QCoreApplicationPrivate *>
+ (QObjectPrivate::get(qApp))->qmljsDebugArgumentsString().isEmpty();
if (hasJSDebugArg || qmlDebugging) {
#if !defined(QT_NO_QML_DEBUGGER)
m_debuggingEnabler = new QQmlDebuggingEnabler(true);
if (!QLoggingCategory::defaultCategory()->isDebugEnabled()) {
- qCCritical(LogQmlRuntime) << "The default 'debug' logging category was disabled. "
- "Re-enabling it for the QML Debugger interface to work correctly.";
+ qCCritical(LogRuntime) << "The default 'debug' logging category was disabled. "
+ "Re-enabling it for the QML Debugger interface to work correctly.";
QLoggingCategory::defaultCategory()->setEnabled(QtDebugMsg, true);
}
#else
- qCWarning(LogSystem) << "The --qml-debug/-qmljsdebugger options are ignored, because Qt was built without support for QML Debugging!";
+ qCWarning(LogSystem) << "The --qml-debug/-qmljsdebugger options are ignored, "
+ "because Qt was built without support for QML Debugging!";
#endif
}
}
-void SharedMain::setupLogging(bool verbose, const QStringList &loggingRules, const QString &messagePattern, const QVariant &useAMConsoleLogger)
+void SharedMain::setupLogging(bool verbose, const QStringList &loggingRules,
+ const QString &messagePattern, const QVariant &useAMConsoleLogger)
{
const QStringList rules = verbose ? QStringList() << qSL("*=true") << qSL("qt.*.debug=false")
: loggingRules.isEmpty() ? QStringList(qSL("*.debug=false"))
diff --git a/src/shared-main-lib/sharedmain.h b/src/shared-main-lib/sharedmain.h
index 7a4cac85..767066de 100644
--- a/src/shared-main-lib/sharedmain.h
+++ b/src/shared-main-lib/sharedmain.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -50,7 +50,6 @@
#endif
QT_FORWARD_DECLARE_STRUCT(QQmlDebuggingEnabler)
-QT_FORWARD_DECLARE_CLASS(QQmlEngine)
QT_BEGIN_NAMESPACE_AM
@@ -60,6 +59,7 @@ public:
SharedMain();
~SharedMain();
+ static void initialize();
static int &preConstructor(int &argc);
void setupIconTheme(const QStringList &themeSearchPaths, const QString &themeName);
void setupQmlDebugging(bool qmlDebugging);
@@ -74,6 +74,7 @@ private:
QQmlDebuggingEnabler *m_debuggingEnabler = nullptr;
#if !defined(AM_HEADLESS)
+ static bool s_initialized;
QSurfaceFormat::OpenGLContextProfile m_requestedOpenGLProfile = QSurfaceFormat::NoProfile;
int m_requestedOpenGLMajorVersion = -1;
int m_requestedOpenGLMinorVersion = -1;
diff --git a/src/src.pro b/src/src.pro
index 590b5811..5b6867bd 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -21,9 +21,7 @@ package_lib.depends = crypto_lib application_lib
manager_lib.subdir = manager-lib
manager_lib.depends = application_lib notification_lib intent_server_lib intent_client_lib monitor_lib plugin_interfaces
-
-installer_lib.subdir = installer-lib
-installer_lib.depends = package_lib manager_lib
+!disable-installer:manager_lib.depends += package_lib crypto_lib
window_lib.subdir = window-lib
window_lib.depends = manager_lib
@@ -44,11 +42,11 @@ launcher_lib.subdir = launcher-lib
launcher_lib.depends = application_lib notification_lib shared_main_lib intent_client_lib
main_lib.subdir = main-lib
-main_lib.depends = shared_main_lib manager_lib installer_lib window_lib monitor_lib
+main_lib.depends = shared_main_lib manager_lib window_lib monitor_lib
!disable-external-dbus-interfaces:qtHaveModule(dbus) {
dbus_lib.subdir = dbus-lib
- dbus_lib.depends = manager_lib installer_lib window_lib
+ dbus_lib.depends = manager_lib window_lib
main_lib.depends += dbus_lib
}
@@ -63,10 +61,10 @@ tools_testrunner.subdir = tools/testrunner
tools_testrunner.depends = main_lib
tools_dumpqmltypes.subdir = tools/dumpqmltypes
-tools_dumpqmltypes.depends = manager_lib installer_lib window_lib shared_main_lib launcher_lib
+tools_dumpqmltypes.depends = manager_lib intent_server_lib window_lib shared_main_lib launcher_lib main_lib
tools_packager.subdir = tools/packager
-tools_packager.depends = package_lib
+tools_packager.depends = package_lib application_lib crypto_lib
tools_uploader.subdir = tools/uploader
tools_uploader.depends = common_lib
@@ -90,7 +88,6 @@ SUBDIRS = \
qtHaveModule(qml):SUBDIRS += \
notification_lib \
manager_lib \
- installer_lib \
window_lib \
monitor_lib \
shared_main_lib \
@@ -106,16 +103,20 @@ SUBDIRS = \
launcher_lib \
# This tool links against everything to extract the Qml type information
- qtHaveModule(qml):qtHaveModule(dbus):!headless:SUBDIRS += \
+ !disable-installer:qtHaveModule(qml):qtHaveModule(dbus):!headless:SUBDIRS += \
tools_dumpqmltypes \
multi-process:qtHaveModule(qml):qtHaveModule(dbus):SUBDIRS += \
tools_launcher_qml \
}
-!cross_compile | tools-only:SUBDIRS += \
- tools_packager \
- tools_uploader \
+!cross_compile | tools-only {
+ !disable-installer:SUBDIRS += \
+ tools_packager
+
+ SUBDIRS += \
+ tools_uploader
+}
qtHaveModule(dbus):SUBDIRS += \
tools_controller \
diff --git a/src/tools/appman/appman.cpp b/src/tools/appman/appman.cpp
index 5523edb9..a907ee6d 100644
--- a/src/tools/appman/appman.cpp
+++ b/src/tools/appman/appman.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -42,17 +43,19 @@
#include <QQmlApplicationEngine>
#include <QQmlContext>
+#include <QCoreApplication>
#include "global.h"
#include "logging.h"
#include "main.h"
-#include "defaultconfiguration.h"
-#include "package.h"
+#include "configuration.h"
+#include "packageutilities.h"
#if !defined(AM_DISABLE_INSTALLER)
# include "sudo.h"
#endif
#include "startuptimer.h"
#include "exception.h"
+#include "qtyaml.h"
#if defined(AM_TESTRUNNER)
# include "testrunner.h"
@@ -70,8 +73,8 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
#else
QCoreApplication::setApplicationName(qSL("Qt Application Manager"));
#endif
- QCoreApplication::setOrganizationName(qSL("Luxoft Sweden AB"));
- QCoreApplication::setOrganizationDomain(qSL("luxoft.com"));
+ QCoreApplication::setOrganizationName(qSL("QtProject"));
+ QCoreApplication::setOrganizationDomain(qSL("qt-project.org"));
QCoreApplication::setApplicationVersion(qSL(AM_VERSION));
Logging::initialize(argc, argv);
@@ -81,7 +84,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
QStringList deploymentWarnings;
#if !defined(AM_DISABLE_INSTALLER)
- Package::ensureCorrectLocale(&deploymentWarnings);
+ PackageUtilities::ensureCorrectLocale(&deploymentWarnings);
Sudo::forkServer(Sudo::DropPrivilegesPermanently, &deploymentWarnings);
StartupTimer::instance()->checkpoint("after sudo server fork");
#endif
@@ -98,12 +101,14 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
bool onlyOnePositionalArgument = true;
#endif
- DefaultConfiguration cfg(additionalDescription, onlyOnePositionalArgument);
+ Configuration cfg(additionalDescription, onlyOnePositionalArgument);
cfg.parse(&deploymentWarnings);
StartupTimer::instance()->checkpoint("after command line parse");
#if defined(AM_TESTRUNNER)
- TestRunner::initialize(cfg.testRunnerArguments());
+ TestRunner::initialize(cfg.mainQmlFile(), cfg.testRunnerArguments());
+ qInfo().nospace().noquote() << "\nTEST: " << cfg.mainQmlFile() << " in "
+ << (cfg.forceMultiProcess() ? "multi" : "single") << "-process mode";
cfg.setForceVerbose(qEnvironmentVariableIsSet("VERBOSE_TEST"));
qInfo() << "Verbose mode is" << (cfg.verbose() ? "on" : "off") << "(changed by (un)setting $VERBOSE_TEST)";
#endif
diff --git a/src/tools/appman/appman.pro b/src/tools/appman/appman.pro
index 03a34391..ed18698c 100644
--- a/src/tools/appman/appman.pro
+++ b/src/tools/appman/appman.pro
@@ -16,9 +16,11 @@ load(install-prefix)
load(build-config)
-exists($$SOURCE_DIR/.tag):GIT_VERSION=$$cat($$SOURCE_DIR/.tag)
-else:unix:exists($$SOURCE_DIR/.git):GIT_VERSION=$$system(cd "$$SOURCE_DIR" && git describe --tags --always --dirty 2>/dev/null)
-isEmpty(GIT_VERSION):GIT_VERSION="unknown"
+GIT_VERSION = $$cat($$SOURCE_DIR/.tag, lines)
+equals(GIT_VERSION, "\$Format:%H\$") {
+ unix:exists($$SOURCE_DIR/.git):GIT_VERSION=$$system(cd "$$SOURCE_DIR" && git describe --tags --always --dirty 2>/dev/null)
+ else:GIT_VERSION="unknown"
+}
createBuildConfig(_DATE_, MODULE_VERSION, GIT_VERSION, SOURCE_DIR, BUILD_DIR, INSTALL_PREFIX, \
QT_ARCH, QT_VERSION, QT_CONFIG, CONFIG, DEFINES, INCLUDEPATH, LIBS)
diff --git a/src/tools/controller/controller.cpp b/src/tools/controller/controller.cpp
index 6c8a8e83..71696b87 100644
--- a/src/tools/controller/controller.cpp
+++ b/src/tools/controller/controller.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -49,7 +49,7 @@
#include <QtAppManCommon/dbus-utilities.h>
#include "applicationmanager_interface.h"
-#include "applicationinstaller_interface.h"
+#include "packagemanager_interface.h"
#include "interrupthandler.h"
@@ -72,13 +72,13 @@ public:
m_manager = new IoQtApplicationManagerInterface(qSL("io.qt.ApplicationManager"), qSL("/ApplicationManager"), conn, this);
}
- void connectToInstaller() Q_DECL_NOEXCEPT_EXPR(false)
+ void connectToPackager() Q_DECL_NOEXCEPT_EXPR(false)
{
- if (m_installer)
+ if (m_packager)
return;
- auto conn = connectTo(qSL("io.qt.ApplicationInstaller"));
- m_installer = new IoQtApplicationInstallerInterface(qSL("io.qt.ApplicationManager"), qSL("/ApplicationInstaller"), conn, this);
+ auto conn = connectTo(qSL("io.qt.PackageManager"));
+ m_packager = new IoQtPackageManagerInterface(qSL("io.qt.ApplicationManager"), qSL("/PackageManager"), conn, this);
}
private:
@@ -111,9 +111,9 @@ private:
}
public:
- IoQtApplicationInstallerInterface *installer() const
+ IoQtPackageManagerInterface *packager() const
{
- return m_installer;
+ return m_packager;
}
IoQtApplicationManagerInterface *manager() const
@@ -122,7 +122,7 @@ public:
}
private:
- IoQtApplicationInstallerInterface *m_installer = nullptr;
+ IoQtPackageManagerInterface *m_packager = nullptr;
IoQtApplicationManagerInterface *m_manager = nullptr;
};
@@ -137,6 +137,8 @@ enum Command {
StopAllApplications,
ListApplications,
ShowApplication,
+ ListPackages,
+ ShowPackage,
InstallPackage,
RemovePackage,
ListInstallationTasks,
@@ -157,6 +159,8 @@ static struct {
{ StopAllApplications, "stop-all-applications", "Stop all applications." },
{ ListApplications, "list-applications", "List all installed applications." },
{ ShowApplication, "show-application", "Show application meta-data." },
+ { ListPackages, "list-packages", "List all installed packages." },
+ { ShowPackage, "show-package", "Show package meta-data." },
{ InstallPackage, "install-package", "Install a package." },
{ RemovePackage, "remove-package", "Remove a package." },
{ ListInstallationTasks, "list-installation-tasks", "List all active installation tasks." },
@@ -188,12 +192,14 @@ static void stopApplication(const QString &appId, bool forceKill = false) Q_DECL
static void stopAllApplications() Q_DECL_NOEXCEPT_EXPR(false);
static void listApplications() Q_DECL_NOEXCEPT_EXPR(false);
static void showApplication(const QString &appId, bool asJson = false) Q_DECL_NOEXCEPT_EXPR(false);
-static void installPackage(const QString &package, const QString &location, bool acknowledge) Q_DECL_NOEXCEPT_EXPR(false);
-static void removePackage(const QString &package, bool keepDocuments, bool force) Q_DECL_NOEXCEPT_EXPR(false);
+static void listPackages() Q_DECL_NOEXCEPT_EXPR(false);
+static void showPackage(const QString &packageId, bool asJson = false) Q_DECL_NOEXCEPT_EXPR(false);
+static void installPackage(const QString &packageUrl, bool acknowledge) Q_DECL_NOEXCEPT_EXPR(false);
+static void removePackage(const QString &packageId, bool keepDocuments, bool force) Q_DECL_NOEXCEPT_EXPR(false);
static void listInstallationTasks() Q_DECL_NOEXCEPT_EXPR(false);
static void cancelInstallationTask(bool all, const QString &taskId) Q_DECL_NOEXCEPT_EXPR(false);
static void listInstallationLocations() Q_DECL_NOEXCEPT_EXPR(false);
-static void showInstallationLocation(const QString &location, bool asJson = false) Q_DECL_NOEXCEPT_EXPR(false);
+static void showInstallationLocation(bool asJson = false) Q_DECL_NOEXCEPT_EXPR(false);
class ThrowingApplication : public QCoreApplication // clazy:exclude=missing-qobject-macro
{
@@ -232,8 +238,8 @@ private:
int main(int argc, char *argv[])
{
QCoreApplication::setApplicationName(qSL("Qt Application Manager Controller"));
- QCoreApplication::setOrganizationName(qSL("Luxoft Sweden AB"));
- QCoreApplication::setOrganizationDomain(qSL("luxoft.com"));
+ QCoreApplication::setOrganizationName(qSL("QtProject"));
+ QCoreApplication::setOrganizationDomain(qSL("qt-project.org"));
QCoreApplication::setApplicationVersion(qSL(AM_VERSION));
ThrowingApplication a(argc, argv);
@@ -381,18 +387,37 @@ int main(int argc, char *argv[])
clp.isSet(qSL("json"))));
break;
+ case ListPackages:
+ clp.process(a);
+ a.runLater(listPackages);
+ break;
+
+ case ShowPackage:
+ clp.addOption({ qSL("json"), qSL("Output in JSON format instead of YAML.") });
+ clp.addPositionalArgument(qSL("package-id"), qSL("The id of an installed package."));
+ clp.process(a);
+
+ if (clp.positionalArguments().size() != 2)
+ clp.showHelp(1);
+
+ a.runLater(std::bind(showPackage,
+ clp.positionalArguments().at(1),
+ clp.isSet(qSL("json"))));
+ break;
+
case InstallPackage:
- clp.addOption({ { qSL("l"), qSL("location") }, qSL("Set a custom installation location."), qSL("installation-location"), qSL("internal-0") });
+ clp.addOption({ { qSL("l"), qSL("location") }, qSL("Set a custom installation location (deprecated and ignored)."), qSL("installation-location"), qSL("internal-0") });
clp.addOption({ { qSL("a"), qSL("acknowledge") }, qSL("Automatically acknowledge the installation (unattended mode).") });
clp.addPositionalArgument(qSL("package"), qSL("The file name of the package; can be - for stdin."));
clp.process(a);
if (clp.positionalArguments().size() != 2)
clp.showHelp(1);
+ if (clp.isSet(qSL("l")))
+ fprintf(stderr, "Ignoring the deprecated -l option.\n");
a.runLater(std::bind(installPackage,
clp.positionalArguments().at(1),
- clp.value(qSL("l")),
clp.isSet(qSL("a"))));
break;
@@ -437,15 +462,16 @@ int main(int argc, char *argv[])
break;
case ShowInstallationLocation:
- clp.addPositionalArgument(qSL("installation-location"), qSL("The id of an installation location."));
+ clp.addPositionalArgument(qSL("installation-location"), qSL("The id of an installation location (deprecated and ignored)."));
clp.addOption({ qSL("json"), qSL("Output in JSON format instead of YAML.") });
clp.process(a);
- if (clp.positionalArguments().size() != 2)
+ if (clp.positionalArguments().size() > 2)
clp.showHelp(1);
+ if (clp.positionalArguments().size() == 2)
+ fprintf(stderr, "Ignoring the deprecated installation-location.\n");
a.runLater(std::bind(showInstallationLocation,
- clp.positionalArguments().at(1),
clp.isSet(qSL("json"))));
break;
}
@@ -601,7 +627,37 @@ void showApplication(const QString &appId, bool asJson) Q_DECL_NOEXCEPT_EXPR(fal
qApp->quit();
}
-void installPackage(const QString &package, const QString &location, bool acknowledge) Q_DECL_NOEXCEPT_EXPR(false)
+void listPackages() Q_DECL_NOEXCEPT_EXPR(false)
+{
+ dbus.connectToPackager();
+
+ auto reply = dbus.packager()->packageIds();
+ reply.waitForFinished();
+ if (reply.isError())
+ throw Exception(Error::IO, "failed to call packageIds via DBus: %1").arg(reply.error().message());
+
+ const auto packageIds = reply.value();
+ for (auto packageId : packageIds)
+ fprintf(stdout, "%s\n", qPrintable(packageId));
+ qApp->quit();
+}
+
+void showPackage(const QString &packageId, bool asJson) Q_DECL_NOEXCEPT_EXPR(false)
+{
+ dbus.connectToPackager();
+
+ auto reply = dbus.packager()->get(packageId);
+ reply.waitForFinished();
+ if (reply.isError())
+ throw Exception(Error::IO, "failed to get package via DBus: %1").arg(reply.error().message());
+
+ QVariant package = reply.value();
+ fprintf(stdout, "%s\n", asJson ? QJsonDocument::fromVariant(package).toJson().constData()
+ : QtYaml::yamlFromVariantDocuments({ package }).constData());
+ qApp->quit();
+}
+
+void installPackage(const QString &package, bool acknowledge) Q_DECL_NOEXCEPT_EXPR(false)
{
QString packageFile = package;
@@ -629,10 +685,10 @@ void installPackage(const QString &package, const QString &location, bool acknow
if (!fi.exists() || !fi.isReadable() || !fi.isFile())
throw Exception(Error::IO, "Package file is not readable: %1").arg(packageFile);
- fprintf(stdout, "Starting installation of package %s to %s...\n", qPrintable(packageFile), qPrintable(location));
+ fprintf(stdout, "Starting installation of package %s ...\n", qPrintable(packageFile));
dbus.connectToManager();
- dbus.connectToInstaller();
+ dbus.connectToPackager();
// all the async lambdas below need to share this variable
static QString installationId;
@@ -640,7 +696,7 @@ void installPackage(const QString &package, const QString &location, bool acknow
// as soon as we have the manifest available: get the app id and acknowledge the installation
if (acknowledge) {
- QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskRequestingInstallationAcknowledge,
+ QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskRequestingInstallationAcknowledge,
[](const QString &taskId, const QVariantMap &metadata) {
if (taskId != installationId)
return;
@@ -648,13 +704,13 @@ void installPackage(const QString &package, const QString &location, bool acknow
if (applicationId.isEmpty())
throw Exception(Error::IO, "could not find a valid application id in the package");
fprintf(stdout, "Acknowledging package installation...\n");
- dbus.installer()->acknowledgePackageInstallation(taskId);
+ dbus.packager()->acknowledgePackageInstallation(taskId);
});
}
// on failure: quit
- QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskFailed,
+ QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskFailed,
[](const QString &taskId, int errorCode, const QString &errorString) {
if (taskId != installationId)
return;
@@ -663,7 +719,7 @@ void installPackage(const QString &package, const QString &location, bool acknow
// on success
- QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskFinished,
+ QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskFinished,
[](const QString &taskId) {
if (taskId != installationId)
return;
@@ -673,7 +729,7 @@ void installPackage(const QString &package, const QString &location, bool acknow
// start the package installation
- auto reply = dbus.installer()->startPackageInstallation(location, fi.absoluteFilePath());
+ auto reply = dbus.packager()->startPackageInstallation(fi.absoluteFilePath());
reply.waitForFinished();
if (reply.isError())
throw Exception(Error::IO, "failed to call startPackageInstallation via DBus: %1").arg(reply.error().message());
@@ -686,7 +742,7 @@ void installPackage(const QString &package, const QString &location, bool acknow
InterruptHandler::install([](int) {
fprintf(stdout, "Cancelling package installation.\n");
- auto reply = dbus.installer()->cancelTask(installationId);
+ auto reply = dbus.packager()->cancelTask(installationId);
reply.waitForFinished();
qApp->exit(1);
});
@@ -697,14 +753,14 @@ void removePackage(const QString &applicationId, bool keepDocuments, bool force)
fprintf(stdout, "Starting removal of package %s...\n", qPrintable(applicationId));
dbus.connectToManager();
- dbus.connectToInstaller();
+ dbus.connectToPackager();
// both the async lambdas below need to share this variables
static QString installationId;
// on failure: quit
- QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskFailed,
+ QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskFailed,
[](const QString &taskId, int errorCode, const QString &errorString) {
if (taskId != installationId)
return;
@@ -713,7 +769,7 @@ void removePackage(const QString &applicationId, bool keepDocuments, bool force)
// on success
- QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskFinished,
+ QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskFinished,
[](const QString &taskId) {
if (taskId != installationId)
return;
@@ -723,7 +779,7 @@ void removePackage(const QString &applicationId, bool keepDocuments, bool force)
// start the package installation
- auto reply = dbus.installer()->removePackage(applicationId, keepDocuments, force);
+ auto reply = dbus.packager()->removePackage(applicationId, keepDocuments, force);
reply.waitForFinished();
if (reply.isError())
throw Exception(Error::IO, "failed to call removePackage via DBus: %1").arg(reply.error().message());
@@ -735,9 +791,9 @@ void removePackage(const QString &applicationId, bool keepDocuments, bool force)
void listInstallationTasks() Q_DECL_NOEXCEPT_EXPR(false)
{
- dbus.connectToInstaller();
+ dbus.connectToPackager();
- auto reply = dbus.installer()->activeTaskIds();
+ auto reply = dbus.packager()->activeTaskIds();
reply.waitForFinished();
if (reply.isError())
throw Exception(Error::IO, "failed to call activeTaskIds via DBus: %1").arg(reply.error().message());
@@ -751,16 +807,16 @@ void listInstallationTasks() Q_DECL_NOEXCEPT_EXPR(false)
void cancelInstallationTask(bool all, const QString &taskId) Q_DECL_NOEXCEPT_EXPR(false)
{
- dbus.connectToInstaller();
+ dbus.connectToPackager();
// both the async lambdas below need to share this variables
static QStringList cancelTaskIds;
static int result = 0;
if (all) {
- dbus.connectToInstaller();
+ dbus.connectToPackager();
- auto reply = dbus.installer()->activeTaskIds();
+ auto reply = dbus.packager()->activeTaskIds();
reply.waitForFinished();
if (reply.isError())
throw Exception(Error::IO, "failed to call activeTaskIds via DBus: %1").arg(reply.error().message());
@@ -777,7 +833,7 @@ void cancelInstallationTask(bool all, const QString &taskId) Q_DECL_NOEXCEPT_EXP
// on task failure
- QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskFailed,
+ QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskFailed,
[](const QString &taskId, int errorCode, const QString &errorString) {
if (cancelTaskIds.removeOne(taskId)) {
if (errorCode != int(Error::Canceled)) {
@@ -794,7 +850,7 @@ void cancelInstallationTask(bool all, const QString &taskId) Q_DECL_NOEXCEPT_EXP
// on success
- QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskFinished,
+ QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskFinished,
[](const QString &taskId) {
if (cancelTaskIds.removeOne(taskId)) {
fprintf(stdout, "Could not cancel task %s anymore - the installation task already finished successfully.\n",
@@ -810,7 +866,7 @@ void cancelInstallationTask(bool all, const QString &taskId) Q_DECL_NOEXCEPT_EXP
// cancel the task
- auto reply = dbus.installer()->cancelTask(cancelTaskId);
+ auto reply = dbus.packager()->cancelTask(cancelTaskId);
reply.waitForFinished();
if (reply.isError())
throw Exception(Error::IO, "failed to call cancelTask via DBus: %1").arg(reply.error().message());
@@ -822,30 +878,20 @@ void cancelInstallationTask(bool all, const QString &taskId) Q_DECL_NOEXCEPT_EXP
void listInstallationLocations() Q_DECL_NOEXCEPT_EXPR(false)
{
- dbus.connectToInstaller();
+ dbus.connectToPackager();
- auto reply = dbus.installer()->installationLocationIds();
- reply.waitForFinished();
- if (reply.isError())
- throw Exception(Error::IO, "failed to call installationLocationIds via DBus: %1").arg(reply.error().message());
-
- const auto installationLocationIds = reply.value();
- for (auto installationLocationId : installationLocationIds)
- fprintf(stdout, "%s\n", qPrintable(installationLocationId));
+ auto installationLocation = dbus.packager()->installationLocation().variant().toMap();
+ if (!installationLocation.isEmpty())
+ fputs("internal-0\n", stdout);
qApp->quit();
}
-void showInstallationLocation(const QString &location, bool asJson) Q_DECL_NOEXCEPT_EXPR(false)
+void showInstallationLocation(bool asJson) Q_DECL_NOEXCEPT_EXPR(false)
{
- dbus.connectToInstaller();
-
- auto reply = dbus.installer()->getInstallationLocation(location);
- reply.waitForFinished();
- if (reply.isError())
- throw Exception(Error::IO, "failed to call getInstallationLocation via DBus: %1").arg(reply.error().message());
+ dbus.connectToPackager();
- QVariant app = reply.value();
- fprintf(stdout, "%s\n", asJson ? QJsonDocument::fromVariant(app).toJson().constData()
- : QtYaml::yamlFromVariantDocuments({ app }).constData());
+ auto installationLocation = dbus.packager()->installationLocation().variant().toMap();
+ fprintf(stdout, "%s\n", asJson ? QJsonDocument::fromVariant(installationLocation).toJson().constData()
+ : QtYaml::yamlFromVariantDocuments({ installationLocation }).constData());
qApp->quit();
}
diff --git a/src/tools/controller/controller.pro b/src/tools/controller/controller.pro
index 973781b9..43af64db 100644
--- a/src/tools/controller/controller.pro
+++ b/src/tools/controller/controller.pro
@@ -16,7 +16,7 @@ appmanif.files = ../../dbus-lib/io.qt.applicationmanager.xml
appmanif.header_flags = -i dbus-utilities.h
DBUS_INTERFACES += \
- ../../dbus-lib/io.qt.applicationinstaller.xml \
+ ../../dbus-lib/io.qt.packagemanager.xml \
appmanif
load(qt_tool)
diff --git a/src/tools/controller/interrupthandler.cpp b/src/tools/controller/interrupthandler.cpp
index 032ea23a..82c4a729 100644
--- a/src/tools/controller/interrupthandler.cpp
+++ b/src/tools/controller/interrupthandler.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/src/tools/controller/interrupthandler.h b/src/tools/controller/interrupthandler.h
index 7674afe2..8bd32d6d 100644
--- a/src/tools/controller/interrupthandler.h
+++ b/src/tools/controller/interrupthandler.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/src/tools/dumpqmltypes/dumpqmltypes.cpp b/src/tools/dumpqmltypes/dumpqmltypes.cpp
index 4d3999d9..ddc52326 100644
--- a/src/tools/dumpqmltypes/dumpqmltypes.cpp
+++ b/src/tools/dumpqmltypes/dumpqmltypes.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -27,7 +28,8 @@
**
****************************************************************************/
-#include <QtAppManInstaller/applicationinstaller.h>
+#include <QtAppManManager/packagemanager.h>
+#include <QtAppManMain/applicationinstaller.h>
#include <QtAppManManager/applicationmanager.h>
#include <QtAppManManager/applicationmodel.h>
#include <QtAppManManager/amnamespace.h>
@@ -43,11 +45,12 @@
#include <QtAppManWindow/windowmanager.h>
#include <QtAppManWindow/window.h>
#include <QtAppManWindow/windowitem.h>
-#include <QtAppManLauncher/qmlapplicationinterface.h>
-#include <QtAppManLauncher/qmlapplicationinterfaceextension.h>
+#include <QtAppManLauncher/dbusapplicationinterface.h>
+#include <QtAppManLauncher/dbusapplicationinterfaceextension.h>
#include <QtAppManLauncher/private/applicationmanagerwindow_p.h>
#include <QtAppManIntentServer/intent.h>
#include <QtAppManIntentServer/intentserver.h>
+#include <QtAppManIntentServer/intentmodel.h>
#include <QtAppManIntentClient/intentclient.h>
#include <QtAppManIntentClient/intentclientrequest.h>
#include <QtAppManIntentClient/intenthandler.h>
@@ -72,14 +75,15 @@ static const QVector<const QMetaObject *> all = {
// manager-lib
&ApplicationManager::staticMetaObject,
&ApplicationInstaller::staticMetaObject,
+ &PackageManager::staticMetaObject,
&NotificationManager::staticMetaObject,
&ApplicationIPCManager::staticMetaObject,
- &AbstractApplication::staticMetaObject,
+ &Application::staticMetaObject,
&AbstractRuntime::staticMetaObject,
&AbstractContainer::staticMetaObject,
&Notification::staticMetaObject,
- &QmlApplicationInterface::staticMetaObject,
- &QmlApplicationInterfaceExtension::staticMetaObject,
+ &DBusApplicationInterface::staticMetaObject,
+ &DBusApplicationInterfaceExtension::staticMetaObject,
&ApplicationManagerWindow::staticMetaObject,
&ApplicationModel::staticMetaObject,
&Am::staticMetaObject,
@@ -99,6 +103,7 @@ static const QVector<const QMetaObject *> all = {
// intent-server-lib
&IntentServer::staticMetaObject,
&Intent::staticMetaObject,
+ &IntentModel::staticMetaObject,
// monitor-lib
&CpuStatus::staticMetaObject,
@@ -250,8 +255,8 @@ int main(int argc, char **argv)
{
try {
QCoreApplication::setApplicationName(qSL("Qt Application Manager QML Types Dumper"));
- QCoreApplication::setOrganizationName(qSL("Luxoft Sweden AB"));
- QCoreApplication::setOrganizationDomain(qSL("luxoft.com"));
+ QCoreApplication::setOrganizationName(qSL("QtProject"));
+ QCoreApplication::setOrganizationDomain(qSL("qt-project.org"));
QCoreApplication::setApplicationVersion(qSL(AM_VERSION));
QCoreApplication a(argc, argv);
diff --git a/src/tools/dumpqmltypes/dumpqmltypes.pro b/src/tools/dumpqmltypes/dumpqmltypes.pro
index 22079782..acde4c97 100644
--- a/src/tools/dumpqmltypes/dumpqmltypes.pro
+++ b/src/tools/dumpqmltypes/dumpqmltypes.pro
@@ -10,13 +10,13 @@ QT *= \
appman_common-private \
appman_application-private \
appman_manager-private \
- appman_installer-private \
appman_notification-private \
appman_window-private \
appman_launcher-private \
appman_intent_client-private \
appman_intent_server-private \
appman_monitor-private \
+ appman_main-private \
appman_shared_main-private \
CONFIG *= console
diff --git a/src/tools/launcher-qml/launcher-qml.cpp b/src/tools/launcher-qml/launcher-qml.cpp
index 12ac1ef3..a7e79f0c 100644
--- a/src/tools/launcher-qml/launcher-qml.cpp
+++ b/src/tools/launcher-qml/launcher-qml.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -73,9 +74,9 @@
# include <QCoreApplication>
#endif
-#include "qmlapplicationinterface.h"
-#include "qmlapplicationinterfaceextension.h"
-#include "qmlnotification.h"
+#include "dbusapplicationinterface.h"
+#include "dbusapplicationinterfaceextension.h"
+#include "dbusnotification.h"
#include "notification.h"
#include "qtyaml.h"
#include "global.h"
@@ -83,7 +84,8 @@
#include "utilities.h"
#include "exception.h"
#include "crashhandler.h"
-#include "yamlapplicationscanner.h"
+#include "yamlpackagescanner.h"
+#include "packageinfo.h"
#include "applicationinfo.h"
#include "startupinterface.h"
#include "dbus-utilities.h"
@@ -102,6 +104,18 @@
#include "memorystatus.h"
#include "monitormodel.h"
+#if defined(AM_HEADLESS)
+# include <QCoreApplication>
+using Application = QCoreApplication;
+#elif defined(AM_ENABLE_WIDGETS)
+# include <QApplication>
+using Application = QApplication;
+#else
+# include <QGuiApplication>
+using Application = QGuiApplication;
+#endif
+
+
QT_USE_NAMESPACE_AM
@@ -110,8 +124,8 @@ int main(int argc, char *argv[])
StartupTimer::instance()->checkpoint("entered main");
QCoreApplication::setApplicationName(qSL("Qt Application Manager QML Launcher"));
- QCoreApplication::setOrganizationName(qSL("Luxoft Sweden AB"));
- QCoreApplication::setOrganizationDomain(qSL("luxoft.com"));
+ QCoreApplication::setOrganizationName(qSL("QtProject"));
+ QCoreApplication::setOrganizationDomain(qSL("qt-project.org"));
QCoreApplication::setApplicationVersion(qSL(AM_VERSION));
if (qEnvironmentVariableIsSet("AM_NO_DLT_LOGGING"))
@@ -123,47 +137,58 @@ int main(int argc, char *argv[])
// As we don't know the app-id yet, we are registering a place holder so we are able to see
// something in the dlt logs if general errors occur.
- Logging::setDltApplicationId("PCLQ", "Luxoft Application-Manager Launcher QML");
+ Logging::setDltApplicationId("QTLQ", "Qt Application-Manager Launcher QML");
Logging::setApplicationId("qml-launcher");
Logging::initialize();
try {
- LauncherMain a(argc, argv);
+ LauncherMain::initialize();
+ Application app(argc, argv);
+ LauncherMain launcher;
QCommandLineParser clp;
clp.addHelpOption();
clp.addOption({ qSL("qml-debug"), qSL("Enables QML debugging and profiling.") });
clp.addOption({ qSL("quicklaunch"), qSL("Starts the launcher in the quicklaunching mode.") });
- clp.addOption({ qSL("directload") , qSL("The info.yaml to start."), qSL("info.yaml") });
- clp.process(a);
+ clp.addOption({ qSL("directload") , qSL("The info.yaml to start (you can add '@<appid>' to start a specific app within the package, instead of the first one)."), qSL("info.yaml") });
+ clp.process(app);
bool quicklaunched = clp.isSet(qSL("quicklaunch"));
- QString directLoad = clp.value(qSL("directload"));
+ QString directLoadManifest = clp.value(qSL("directload"));
- if (directLoad.isEmpty())
- a.loadConfiguration();
+ if (directLoadManifest.isEmpty())
+ launcher.loadConfiguration();
- CrashHandler::setCrashActionConfiguration(a.runtimeConfiguration().value(qSL("crashAction")).toMap());
- a.setupLogging(false, a.loggingRules(), QString(), a.useAMConsoleLogger()); // the verbose flag has already been factored into the rules
- a.setupQmlDebugging(clp.isSet(qSL("qml-debug")));
- a.setupOpenGL(a.openGLConfiguration());
- a.setupIconTheme(a.iconThemeSearchPaths(), a.iconThemeName());
- a.registerWaylandExtensions();
+ CrashHandler::setCrashActionConfiguration(launcher.runtimeConfiguration().value(qSL("crashAction")).toMap());
+ // the verbose flag has already been factored into the rules:
+ launcher.setupLogging(false, launcher.loggingRules(), QString(), launcher.useAMConsoleLogger());
+ launcher.setupQmlDebugging(clp.isSet(qSL("qml-debug")));
+ launcher.setupOpenGL(launcher.openGLConfiguration());
+ launcher.setupIconTheme(launcher.iconThemeSearchPaths(), launcher.iconThemeName());
+ launcher.registerWaylandExtensions();
StartupTimer::instance()->checkpoint("after basic initialization");
- if (!directLoad.isEmpty()) {
- QFileInfo fi(directLoad);
+ if (!directLoadManifest.isEmpty()) {
+ QString directLoadAppId;
+ int appPos = directLoadManifest.indexOf(qSL("@"));
+ if (appPos > 0) {
+ directLoadAppId = directLoadManifest.mid(appPos + 1);
+ directLoadManifest.truncate(appPos);
+ }
+
+ QFileInfo fi(directLoadManifest);
if (!fi.exists() || fi.fileName() != qSL("info.yaml"))
throw Exception("--directload needs a valid info.yaml file as parameter");
- directLoad = fi.absoluteFilePath();
+ directLoadManifest = fi.absoluteFilePath();
+ new Controller(&launcher, quicklaunched, qMakePair(directLoadManifest, directLoadAppId));
} else {
- a.setupDBusConnections();
+ launcher.setupDBusConnections();
StartupTimer::instance()->checkpoint("after dbus initialization");
+ new Controller(&launcher, quicklaunched);
}
- new Controller(&a, quicklaunched, directLoad);
- return a.exec();
+ return app.exec();
} catch (const std::exception &e) {
qCCritical(LogQmlRuntime) << "ERROR:" << e.what();
@@ -171,19 +196,23 @@ int main(int argc, char *argv[])
}
}
+Controller::Controller(LauncherMain *a, bool quickLaunched)
+ : Controller(a, quickLaunched, qMakePair(QString{}, QString{}))
+{ }
-Controller::Controller(LauncherMain *a, bool quickLaunched, const QString &directLoad)
- : QObject(a)
+Controller::Controller(LauncherMain *launcher, bool quickLaunched, const QPair<QString, QString> &directLoad)
+ : QObject(launcher)
, m_quickLaunched(quickLaunched)
{
- connect(&m_engine, &QObject::destroyed, a, &QCoreApplication::quit);
+ connect(&m_engine, &QObject::destroyed, QCoreApplication::instance(), &QCoreApplication::quit);
CrashHandler::setQmlEngine(&m_engine);
#if !defined(AM_HEADLESS)
qmlRegisterType<ApplicationManagerWindow>("QtApplicationManager.Application", 2, 0, "ApplicationManagerWindow");
#endif
- qmlRegisterType<QmlNotification>("QtApplicationManager", 2, 0, "Notification");
- qmlRegisterType<QmlApplicationInterfaceExtension>("QtApplicationManager.Application", 2, 0, "ApplicationInterfaceExtension");
+ qmlRegisterType<DBusNotification>("QtApplicationManager", 2, 0, "Notification");
+ qmlRegisterType<DBusApplicationInterfaceExtension>("QtApplicationManager.Application", 2, 0,
+ "ApplicationInterfaceExtension");
// monitor-lib
qmlRegisterType<CpuStatus>("QtApplicationManager", 2, 0, "CpuStatus");
@@ -205,13 +234,19 @@ Controller::Controller(LauncherMain *a, bool quickLaunched, const QString &direc
qmlRegisterType<MemoryStatus>("QtApplicationManager", 1, 0, "MemoryStatus");
qmlRegisterType<MonitorModel>("QtApplicationManager", 1, 0, "MonitorModel");
- m_configuration = a->runtimeConfiguration();
+ m_configuration = launcher->runtimeConfiguration();
+
+ const QStringList resources = variantToStringList(m_configuration.value(qSL("resources")));
+ for (const QString &resource: resources) {
+ if (!loadResource(resource))
+ qCWarning(LogSystem) << "Cannot register resource:" << resource;
+ }
QString absolutePluginPath;
QStringList pluginPaths = variantToStringList(m_configuration.value(qSL("pluginPaths")));
for (QString &path : pluginPaths) {
if (QFileInfo(path).isRelative())
- path.prepend(a->baseDir());
+ path.prepend(launcher->baseDir());
else if (absolutePluginPath.isEmpty())
absolutePluginPath = path;
@@ -226,12 +261,10 @@ Controller::Controller(LauncherMain *a, bool quickLaunched, const QString &direc
QString absoluteImportPath;
QStringList importPaths = variantToStringList(m_configuration.value(qSL("importPaths")));
for (QString &path : importPaths) {
- if (QFileInfo(path).isRelative())
- path.prepend(a->baseDir());
- else if (absoluteImportPath.isEmpty())
+ const QFileInfo fi(path);
+ if (fi.isNativePath() && fi.isAbsolute() && absoluteImportPath.isEmpty())
absoluteImportPath = path;
-
- m_engine.addImportPath(path);
+ m_engine.addImportPath(toAbsoluteFilePath(path, launcher->baseDir()));
}
if (!absoluteImportPath.isEmpty()) {
@@ -255,12 +288,9 @@ Controller::Controller(LauncherMain *a, bool quickLaunched, const QString &direc
StartupTimer::instance()->checkpoint("after window registration");
- QString quicklaunchQml = m_configuration.value((qSL("quicklaunchQml"))).toString();
+ const QString quicklaunchQml = m_configuration.value((qSL("quicklaunchQml"))).toString();
if (!quicklaunchQml.isEmpty() && quickLaunched) {
- if (QFileInfo(quicklaunchQml).isRelative())
- quicklaunchQml.prepend(a->baseDir());
-
- QQmlComponent quicklaunchComp(&m_engine, quicklaunchQml);
+ QQmlComponent quicklaunchComp(&m_engine, filePathToUrl(quicklaunchQml, launcher->baseDir()));
if (!quicklaunchComp.isError()) {
QScopedPointer<QObject> quicklaunchInstance(quicklaunchComp.create());
quicklaunchComp.completeCreate();
@@ -271,23 +301,42 @@ Controller::Controller(LauncherMain *a, bool quickLaunched, const QString &direc
}
}
- if (directLoad.isEmpty()) {
- m_applicationInterface = new QmlApplicationInterface(a->p2pDBusName(), a->notificationDBusName(), this);
- connect(m_applicationInterface, &QmlApplicationInterface::startApplication,
+ if (directLoad.first.isEmpty()) {
+ m_applicationInterface = new DBusApplicationInterface(launcher->p2pDBusName(),
+ launcher->notificationDBusName(), this);
+ connect(m_applicationInterface, &DBusApplicationInterface::startApplication,
this, &Controller::startApplication);
- if (!m_applicationInterface->initialize())
+ if (!m_applicationInterface->initialize(true))
throw Exception("Could not connect to the application manager's ApplicationInterface on the peer D-Bus");
} else {
QMetaObject::invokeMethod(this, [this, directLoad]() {
- QFileInfo fi(directLoad);
- YamlApplicationScanner yas;
+ PackageInfo *pi;
try {
- ApplicationInfo *a = yas.scan(directLoad);
- startApplication(fi.absolutePath(), a->codeFilePath(), QString(), QString(), a->toVariantMap(), QVariantMap());
+ pi = YamlPackageScanner().scan(directLoad.first);
} catch (const Exception &e) {
- throw Exception("Could not parse info.yaml file: %1").arg(e.what());
+ qCCritical(LogQmlRuntime) << "Could not parse info.yaml file:" << e.what();
+ QCoreApplication::exit(20);
+ return;
}
+ const auto apps = pi->applications();
+ const ApplicationInfo *a = apps.constFirst();
+ if (!directLoad.second.isEmpty()) {
+ auto it = std::find_if(apps.cbegin(), apps.cend(),
+ [appId = directLoad.second](ApplicationInfo *appInfo) -> bool {
+ return (appInfo->id() == appId);
+ });
+ if (it == apps.end()) {
+ qCCritical(LogQmlRuntime) << "Could not find the requested application id"
+ << directLoad.second << "within the info.yaml file";
+ QCoreApplication::exit(21);
+ return;
+ }
+ a = *it;
+ }
+
+ startApplication(QFileInfo(directLoad.first).absolutePath(), a->codeFilePath(),
+ QString(), QString(), a->toVariantMap(), QVariantMap());
}, Qt::QueuedConnection);
}
@@ -364,7 +413,18 @@ void Controller::startApplication(const QString &baseDir, const QString &qmlFile
return;
}
- if (!QFile::exists(qmlFile)) {
+ QVariant resVar = runtimeParameters.value(qSL("resources"));
+ const QVariantList resources = (resVar.type() == QVariant::String) ? QVariantList{resVar}
+ : qdbus_cast<QVariantList>(resVar);
+ for (const QVariant &resource : resources) {
+ if (!loadResource(resource.toString()))
+ qCWarning(LogQmlRuntime) << "Cannot register resource:" << resource.toString();
+ }
+
+ const QUrl qmlFileUrl = filePathToUrl(qmlFile, baseDir);
+ const QString qmlFileStr = urlToLocalFilePath(qmlFileUrl);
+
+ if (!QFile::exists(qmlFileStr)) {
qCCritical(LogQmlRuntime) << "could not load" << qmlFile << ": file does not exist";
QCoreApplication::exit(2);
return;
@@ -414,7 +474,7 @@ void Controller::startApplication(const QString &baseDir, const QString &qmlFile
if (loadDummyData) {
qCDebug(LogQmlRuntime) << "loading dummy-data";
- loadQmlDummyDataFiles(&m_engine, QFileInfo(qmlFile).path());
+ loadQmlDummyDataFiles(&m_engine, QFileInfo(qmlFileStr).path());
}
QVariant pluginPaths = runtimeParameters.value(qSL("pluginPaths"));
@@ -434,8 +494,9 @@ void Controller::startApplication(const QString &baseDir, const QString &qmlFile
: qdbus_cast<QVariantList>(imports);
for (const QVariant &v : ipvl) {
const QString path = v.toString();
- if (QFileInfo(path).isRelative())
- m_engine.addImportPath(QDir().absoluteFilePath(path));
+ const QFileInfo fi(path);
+ if (!(fi.isNativePath() && fi.isAbsolute()))
+ m_engine.addImportPath(toAbsoluteFilePath(path));
else
qCWarning(LogQmlRuntime) << "Omitting absolute import path in info file for safety reasons:" << path;
}
@@ -452,7 +513,6 @@ void Controller::startApplication(const QString &baseDir, const QString &qmlFile
qmlProtectModule("QtApplicationManager", 2);
qmlProtectModule("QtApplicationManager.Application", 2);
- QUrl qmlFileUrl = QUrl::fromLocalFile(qmlFile);
m_engine.rootContext()->setContextProperty(qSL("StartupTimer"), StartupTimer::instance());
m_engine.load(qmlFileUrl);
@@ -461,7 +521,7 @@ void Controller::startApplication(const QString &baseDir, const QString &qmlFile
auto topLevels = m_engine.rootObjects();
if (Q_UNLIKELY(topLevels.isEmpty() || !topLevels.at(0))) {
- qCCritical(LogSystem) << "could not load" << qmlFile << ": no root object";
+ qCCritical(LogSystem) << "could not load" << qmlFileStr << ": no root object";
QCoreApplication::exit(3);
return;
}
diff --git a/src/tools/launcher-qml/launcher-qml_p.h b/src/tools/launcher-qml/launcher-qml_p.h
index e0e54eef..10bed12a 100644
--- a/src/tools/launcher-qml/launcher-qml_p.h
+++ b/src/tools/launcher-qml/launcher-qml_p.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -67,14 +68,15 @@ protected:
class LauncherMain;
-class QmlApplicationInterface;
+class DBusApplicationInterface;
class Controller : public QObject
{
Q_OBJECT
public:
- Controller(LauncherMain *a, bool quickLaunched, const QString &directLoad = QString());
+ Controller(LauncherMain *a, bool quickLaunched);
+ Controller(LauncherMain *a, bool quickLaunched, const QPair<QString, QString> &directLoad);
public slots:
void startApplication(const QString &baseDir, const QString &qmlFile, const QString &document,
@@ -83,7 +85,7 @@ public slots:
private:
QQmlApplicationEngine m_engine;
- QmlApplicationInterface *m_applicationInterface = nullptr;
+ DBusApplicationInterface *m_applicationInterface = nullptr;
QVariantMap m_configuration;
bool m_launched = false;
bool m_quickLaunched;
diff --git a/src/tools/packager/packager.cpp b/src/tools/packager/packager.cpp
index 5f81a7f0..a03ddb97 100644
--- a/src/tools/packager/packager.cpp
+++ b/src/tools/packager/packager.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -40,7 +41,7 @@
#include <QtAppManCommon/exception.h>
#include <QtAppManCommon/qtyaml.h>
#include <QtAppManCommon/utilities.h>
-#include <QtAppManPackage/package.h>
+#include <QtAppManPackage/packageutilities.h>
#include "packagingjob.h"
QT_USE_NAMESPACE_AM
@@ -87,16 +88,16 @@ static Command command(QCommandLineParser &clp)
int main(int argc, char *argv[])
{
- Package::ensureCorrectLocale();
+ PackageUtilities::ensureCorrectLocale();
QCoreApplication::setApplicationName(qSL("Qt ApplicationManager Packager"));
- QCoreApplication::setOrganizationName(qSL("Luxoft Sweden AB"));
- QCoreApplication::setOrganizationDomain(qSL("luxoft.com"));
+ QCoreApplication::setOrganizationName(qSL("QtProject"));
+ QCoreApplication::setOrganizationDomain(qSL("qt-project.org"));
QCoreApplication::setApplicationVersion(qSL(AM_VERSION));
QCoreApplication a(argc, argv);
- if (!Package::checkCorrectLocale()) {
+ if (!PackageUtilities::checkCorrectLocale()) {
fprintf(stderr, "ERROR: the packager needs a UTF-8 locale to work correctly:\n"
" even automatically switching to C.UTF-8 or en_US.UTF-8 failed.\n");
exit(2);
@@ -176,13 +177,14 @@ int main(int argc, char *argv[])
metadata.append(qMakePair(snippet.toUtf8(), QString()));
for (const auto &md : metadata) {
- QtYaml::ParseError parseError;
- const QVector<QVariant> docs = QtYaml::variantDocumentsFromYaml(md.first, &parseError);
- if (parseError.error != QJsonParseError::NoError) {
- throw Exception(Error::IO, "YAML parse error in --extra-%4metadata%5 %6 at line %1, column %2: %3")
- .arg(parseError.line).arg(parseError.column).arg(parseError.errorString())
+ QVector<QVariant> docs;
+ try {
+ docs = YamlParser::parseAllDocuments(md.first);
+ } catch (const Exception &e) {
+ throw Exception(Error::IO, "in --extra-%1metadata%2 %3: %4")
.arg(isSigned ? "signed-" : "").arg(md.second.isEmpty() ? "": "-file")
- .arg(md.second.isEmpty() ? qSL("option") : md.second);
+ .arg(md.second.isEmpty() ? qSL("option") : md.second)
+ .arg(e.errorString());
}
if (docs.size() < 1) {
throw Exception("Could not parse --extra-%1metadata%2 %3: Invalid document format")
@@ -294,12 +296,8 @@ int main(int argc, char *argv[])
} else if (!yaml.open(QIODevice::ReadOnly)) {
throw Exception(yaml, "Could not open YAML input file");
}
- QtYaml::ParseError error;
- auto docs = QtYaml::variantDocumentsFromYaml(yaml.readAll(), &error);
- if (docs.isEmpty()) {
- throw Exception("Failed to parse YAML file: %1 at line %2, column %3")
- .arg(error.errorString()).arg(error.line).arg(error.column);
- }
+
+ QVector<QVariant> docs = YamlParser::parseAllDocuments(yaml.readAll());
QJsonDocument json;
if (clp.isSet(qSL("i"))) {
bool isInt;
diff --git a/src/tools/packager/packagingjob.cpp b/src/tools/packager/packagingjob.cpp
index b2295d44..53c35a7f 100644
--- a/src/tools/packager/packagingjob.cpp
+++ b/src/tools/packager/packagingjob.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -42,9 +43,10 @@
#include "exception.h"
#include "signature.h"
#include "qtyaml.h"
+#include "packageinfo.h"
#include "applicationinfo.h"
+#include "intentinfo.h"
#include "installationreport.h"
-#include "yamlapplicationscanner.h"
#include "packageextractor.h"
#include "packagecreator.h"
@@ -149,22 +151,37 @@ void PackagingJob::execute() Q_DECL_NOEXCEPT_EXPR(false)
throw Exception(Error::Package, "source %1 is not a directory").arg(m_sourceDir);
// check metadata
- YamlApplicationScanner yas;
- QString infoName = yas.metaDataFileName();
- QScopedPointer<ApplicationInfo> app(yas.scan(source.absoluteFilePath(infoName)));
+ QString infoName = qSL("info.yaml");
+ QScopedPointer<PackageInfo> package(PackageInfo::fromManifest(source.absoluteFilePath(infoName)));
// build report
- InstallationReport report(app->id());
+ InstallationReport report(package->id());
report.addFile(infoName);
// check icon
- if (!QFile::exists(source.absoluteFilePath(app->icon())))
+ if (!QFile::exists(source.absoluteFilePath(package->icon())))
throw Exception(Error::Package, "missing the file referenced by the 'icon' field");
- report.addFile(app->icon());
+ report.addFile(package->icon());
+
+ // check intent icons
+ auto intents = package->intents();
+ for (const auto intent : intents) {
+ if (!QFile::exists(source.absoluteFilePath(intent->icon()))) {
+ throw Exception(Error::Package, "missing the file referenced by the 'icon' field for intent '%1'")
+ .arg(intent->id());
+ }
+ }
- // check executable
- if (!QFile::exists(source.absoluteFilePath(app->codeFilePath())))
- throw Exception(Error::Package, "missing the file referenced by the 'code' field");
+ // check executables
+ auto applications = package->applications();
+ if (applications.isEmpty())
+ throw Exception(Error::Package, "no applications defined in package");
+ for (const auto application : applications) {
+ if (!QFile::exists(source.absoluteFilePath(application->codeFilePath()))) {
+ throw Exception(Error::Package, "missing the file referenced by the 'code' field for application '%1'")
+ .arg(application->id());
+ }
+ }
quint64 estimatedImageSize = 0;
QString canonicalSourcePath = source.canonicalPath();
@@ -188,16 +205,16 @@ void PackagingJob::execute() Q_DECL_NOEXCEPT_EXPR(false)
if (entryInfo.fileName().startsWith(qL1S("--PACKAGE-")))
throw Exception(Error::Package, "file names starting with --PACKAGE- are reserved by the packager (found: %1)").arg(entryPath);
- estimatedImageSize += (entryInfo.size() + Ext2BlockSize - 1) / Ext2BlockSize;
+ estimatedImageSize += (quint64(entryInfo.size()) + Ext2BlockSize - 1) / Ext2BlockSize;
- if (entryPath != infoName && entryPath != app->icon())
+ if (entryPath != infoName && entryPath != package->icon())
report.addFile(entryPath);
}
// we have the estimatedImageSize for the raw content now, but we need to add the inode
// overhead still. This algorithm comes from buildroot:
// http://git.buildroot.net/buildroot/tree/package/mke2img/mke2img
- estimatedImageSize = (500 + (estimatedImageSize + report.files().count() + 400 / 8) * 11 / 10) * Ext2BlockSize;
+ estimatedImageSize = (500 + (estimatedImageSize + quint64(report.files().count()) + 400 / 8) * 11 / 10) * Ext2BlockSize;
report.setDiskSpaceUsed(estimatedImageSize);
// set extra metadata
@@ -207,11 +224,11 @@ void PackagingJob::execute() Q_DECL_NOEXCEPT_EXPR(false)
// finally create the package
PackageCreator creator(source, &destination, report);
if (!creator.create())
- throw Exception(Error::Package, "could not create package %1: %2").arg(app->id()).arg(creator.errorString());
+ throw Exception(Error::Package, "could not create package %1: %2").arg(package->id()).arg(creator.errorString());
QVariantMap md = creator.metaData();
- m_output = m_asJson ? QJsonDocument::fromVariant(md).toJson().constData()
- : QtYaml::yamlFromVariantDocuments({ md }).constData();
+ m_output = QString::fromUtf8(m_asJson ? QJsonDocument::fromVariant(md).toJson()
+ : QtYaml::yamlFromVariantDocuments({ md }));
break;
}
case DeveloperSign:
@@ -316,8 +333,8 @@ void PackagingJob::execute() Q_DECL_NOEXCEPT_EXPR(false)
throw Exception(Error::Package, "could not create package %1: %2").arg(m_destinationName).arg(creator.errorString());
QVariantMap md = creator.metaData();
- m_output = m_asJson ? QJsonDocument::fromVariant(md).toJson().constData()
- : QtYaml::yamlFromVariantDocuments({ md }).constData();
+ m_output = QString::fromUtf8(m_asJson ? QJsonDocument::fromVariant(md).toJson()
+ : QtYaml::yamlFromVariantDocuments({ md }));
break;
}
default:
diff --git a/src/tools/packager/packagingjob.h b/src/tools/packager/packagingjob.h
index a46ac278..9c5125c0 100644
--- a/src/tools/packager/packagingjob.h
+++ b/src/tools/packager/packagingjob.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/src/tools/testrunner/testrunner.cpp b/src/tools/testrunner/testrunner.cpp
index 33f03a69..ce10cefd 100644
--- a/src/tools/testrunner/testrunner.cpp
+++ b/src/tools/testrunner/testrunner.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -47,6 +47,8 @@
#include <QQmlEngine>
#include <QRegExp>
#include <QRegularExpression>
+#include <QDir>
+#include <QFileInfo>
#include <qlogging.h>
#include <QtTest/qtestsystem.h>
@@ -168,19 +170,26 @@ static QObject *amTest(QQmlEngine *engine, QJSEngine *jsEngine)
return AmTest::instance();
}
-void TestRunner::initialize(const QStringList &testRunnerArguments)
+void TestRunner::initialize(const QString &testFile, const QStringList &testRunnerArguments)
{
Q_ASSERT(!testRunnerArguments.isEmpty());
+ const QString name = QFileInfo(testRunnerArguments.at(0)).fileName() + "::" + QDir().relativeFilePath(testFile);
+ static const char *programName = strdup(name.toLocal8Bit().constData());
+ QuickTestResult::setProgramName(programName);
+
// Convert all the arguments back into a char * array.
// These need to be alive as long as the program is running!
static QVector<char *> testArgV;
for (const auto &arg : testRunnerArguments)
testArgV << strdup(arg.toLocal8Bit().constData());
- atexit([]() { std::for_each(testArgV.constBegin(), testArgV.constEnd(), free); });
+
+ atexit([]() {
+ free(const_cast<char*>(programName));
+ std::for_each(testArgV.constBegin(), testArgV.constEnd(), free);
+ });
QuickTestResult::setCurrentAppname(testArgV.constFirst());
- QuickTestResult::setProgramName(testArgV.constFirst());
// Allocate a QuickTestResult to create QBenchmarkGlobalData, otherwise the benchmark options don't work
QuickTestResult result;
diff --git a/src/tools/testrunner/testrunner.h b/src/tools/testrunner/testrunner.h
index 5cc1a50d..00d2240c 100644
--- a/src/tools/testrunner/testrunner.h
+++ b/src/tools/testrunner/testrunner.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE_AM
class TestRunner
{
public:
- static void initialize(const QStringList &testRunnerArguments);
+ static void initialize(const QString &testFile, const QStringList &testRunnerArguments);
static int exec(QQmlEngine *engine);
};
diff --git a/src/tools/testrunner/testrunner_p.h b/src/tools/testrunner/testrunner_p.h
index 614e66c6..bc29c250 100644
--- a/src/tools/testrunner/testrunner_p.h
+++ b/src/tools/testrunner/testrunner_p.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/tools/uploader/uploader.cpp b/src/tools/uploader/uploader.cpp
index 40d9a66c..9912593c 100644
--- a/src/tools/uploader/uploader.cpp
+++ b/src/tools/uploader/uploader.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -91,8 +91,8 @@ Q_NORETURN void printErrorAndExit(const QString &errorPrefix, const QString &err
int main(int argc, char *argv[])
{
QCoreApplication::setApplicationName(applicationName);
- QCoreApplication::setOrganizationName(qSL("Luxoft"));
- QCoreApplication::setOrganizationDomain(qSL("luxoft.com"));
+ QCoreApplication::setOrganizationName(qSL("QtProject"));
+ QCoreApplication::setOrganizationDomain(qSL("qt-project.org"));
QCoreApplication::setApplicationVersion(qSL(AM_VERSION));
QCoreApplication a(argc, argv);
diff --git a/src/wayland-extensions/qtam-extension.xml b/src/wayland-extensions/qtam-extension.xml
index a80600a8..73025015 100644
--- a/src/wayland-extensions/qtam-extension.xml
+++ b/src/wayland-extensions/qtam-extension.xml
@@ -4,7 +4,7 @@
Copyright (C) 2018 Pelagicore AG
Contact: https://www.qt.io/licensing/
- This file is part of the Luxoft Application Manager.
+ This file is part of the Qt Application Manager.
$QT_BEGIN_LICENSE:BSD-QTAS$
Commercial License Usage
diff --git a/src/window-lib/inprocesswindow.cpp b/src/window-lib/inprocesswindow.cpp
index 8b55df29..aa9a4906 100644
--- a/src/window-lib/inprocesswindow.cpp
+++ b/src/window-lib/inprocesswindow.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -45,7 +45,7 @@
QT_BEGIN_NAMESPACE_AM
-InProcessWindow::InProcessWindow(AbstractApplication *app, const QSharedPointer<InProcessSurfaceItem> &surfaceItem)
+InProcessWindow::InProcessWindow(Application *app, const QSharedPointer<InProcessSurfaceItem> &surfaceItem)
: Window(app)
, m_surfaceItem(surfaceItem)
{
diff --git a/src/window-lib/inprocesswindow.h b/src/window-lib/inprocesswindow.h
index a88c648c..3b4575b3 100644
--- a/src/window-lib/inprocesswindow.h
+++ b/src/window-lib/inprocesswindow.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -56,7 +56,7 @@ class InProcessWindow : public Window
Q_OBJECT
public:
- InProcessWindow(AbstractApplication *app, const QSharedPointer<InProcessSurfaceItem> &surfaceItem);
+ InProcessWindow(Application *app, const QSharedPointer<InProcessSurfaceItem> &surfaceItem);
virtual ~InProcessWindow();
bool isInProcess() const override { return true; }
diff --git a/src/window-lib/touchemulation.cpp b/src/window-lib/touchemulation.cpp
index 6b989069..985887f7 100644
--- a/src/window-lib/touchemulation.cpp
+++ b/src/window-lib/touchemulation.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/window-lib/touchemulation.h b/src/window-lib/touchemulation.h
index 4dc9e937..caf967b1 100644
--- a/src/window-lib/touchemulation.h
+++ b/src/window-lib/touchemulation.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/window-lib/touchemulation_x11.cpp b/src/window-lib/touchemulation_x11.cpp
index 419cd1b9..927f8e94 100644
--- a/src/window-lib/touchemulation_x11.cpp
+++ b/src/window-lib/touchemulation_x11.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/window-lib/touchemulation_x11_p.h b/src/window-lib/touchemulation_x11_p.h
index 7719cb21..14657ac6 100644
--- a/src/window-lib/touchemulation_x11_p.h
+++ b/src/window-lib/touchemulation_x11_p.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/window-lib/waylandcompositor.cpp b/src/window-lib/waylandcompositor.cpp
index 6bf0d18b..fb2a3ccf 100644
--- a/src/window-lib/waylandcompositor.cpp
+++ b/src/window-lib/waylandcompositor.cpp
@@ -5,7 +5,7 @@
** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -54,13 +54,9 @@
#include "waylandcompositor.h"
#include <QWaylandWlShell>
-#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
-# include <QWaylandXdgShell>
-# if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
-# include <private/qwaylandxdgshell_p.h>
-# endif
-#else
-# include <QWaylandXdgShellV5>
+#include <QWaylandXdgShell>
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+# include <private/qwaylandxdgshell_p.h>
#endif
#include <QWaylandQuickOutput>
#include <QWaylandTextInputManager>
@@ -85,15 +81,10 @@ void WindowSurface::setShellSurface(QWaylandWlShellSurface *shellSurface)
void WindowSurface::sendResizing(const QSize &size)
{
-#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
if (m_topLevel)
m_topLevel->sendResizing(size);
else if (m_popup)
; // do nothing
-#else
- if (m_xdgSurface)
- m_xdgSurface->sendResizing(size);
-#endif
else
m_wlSurface->sendConfigure(size, QWaylandWlShellSurface::NoneEdge);
}
@@ -142,30 +133,23 @@ void WindowSurface::ping()
void WindowSurface::close()
{
-#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
if (m_topLevel) {
m_topLevel->sendClose();
} else if (m_popup) {
-# if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
QWaylandXdgPopupPrivate::get(m_popup)->send_popup_done();
-# else
+#else
m_popup->sendPopupDone();
-# endif
+#endif
} else {
qCWarning(LogGraphics) << "The Wayland surface" << this << "is not using the XDG Shell extension. Unable to send close signal.";
}
-#else
- if (m_xdgSurface)
- m_xdgSurface->sendClose();
- else
- qCWarning(LogGraphics) << this << "is not using the XDG V5 Shell extension. Unable to send close signal.";
-#endif
}
WaylandCompositor::WaylandCompositor(QQuickWindow *window, const QString &waylandSocketName)
: QWaylandQuickCompositor()
, m_wlShell(new QWaylandWlShell(this))
- , m_xdgShell(new WaylandXdgShell(this))
+ , m_xdgShell(new QWaylandXdgShell(this))
, m_amExtension(new WaylandQtAMServerExtension(this))
, m_textInputManager(new QWaylandTextInputManager(this))
{
@@ -176,12 +160,10 @@ WaylandCompositor::WaylandCompositor(QQuickWindow *window, const QString &waylan
connect(m_wlShell, &QWaylandWlShell::wlShellSurfaceRequested, this, &WaylandCompositor::createWlSurface);
- connect(m_xdgShell, &WaylandXdgShell::xdgSurfaceCreated, this, &WaylandCompositor::onXdgSurfaceCreated);
-#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
+ connect(m_xdgShell, &QWaylandXdgShell::xdgSurfaceCreated, this, &WaylandCompositor::onXdgSurfaceCreated);
connect(m_xdgShell, &QWaylandXdgShell::toplevelCreated, this, &WaylandCompositor::onTopLevelCreated);
connect(m_xdgShell, &QWaylandXdgShell::popupCreated, this, &WaylandCompositor::onPopupCreated);
-#endif
- connect(m_xdgShell, &WaylandXdgShell::pong, this, &WaylandCompositor::onXdgPongReceived);
+ connect(m_xdgShell, &QWaylandXdgShell::pong, this, &WaylandCompositor::onXdgPongReceived);
auto wmext = new QWaylandQtWindowManager(this);
connect(wmext, &QWaylandQtWindowManager::openUrl, this, [](QWaylandClient *client, const QUrl &url) {
@@ -241,7 +223,7 @@ void WaylandCompositor::createWlSurface(QWaylandSurface *surface, const QWayland
}
-void WaylandCompositor::onXdgSurfaceCreated(WaylandXdgSurface *xdgSurface)
+void WaylandCompositor::onXdgSurfaceCreated(QWaylandXdgSurface *xdgSurface)
{
WindowSurface *windowSurface = static_cast<WindowSurface*>(xdgSurface->surface());
@@ -254,7 +236,6 @@ void WaylandCompositor::onXdgSurfaceCreated(WaylandXdgSurface *xdgSurface)
});
}
-#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
void WaylandCompositor::onTopLevelCreated(QWaylandXdgToplevel *topLevel, QWaylandXdgSurface *xdgSurface)
{
WindowSurface *windowSurface = static_cast<WindowSurface*>(xdgSurface->surface());
@@ -277,6 +258,5 @@ void WaylandCompositor::onPopupCreated(QWaylandXdgPopup *popup, QWaylandXdgSurfa
connect(popup, &QWaylandXdgPopup::configuredGeometryChanged,
windowSurface, &WindowSurface::popupGeometryChanged);
}
-#endif
QT_END_NAMESPACE_AM
diff --git a/src/window-lib/waylandcompositor.h b/src/window-lib/waylandcompositor.h
index 283db83a..5d554d16 100644
--- a/src/window-lib/waylandcompositor.h
+++ b/src/window-lib/waylandcompositor.h
@@ -5,7 +5,7 @@
** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -59,23 +59,11 @@ QT_FORWARD_DECLARE_CLASS(QWaylandWlShell)
QT_FORWARD_DECLARE_CLASS(QWaylandWlShellSurface)
QT_FORWARD_DECLARE_CLASS(QWaylandTextInputManager)
-#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
-
QT_FORWARD_DECLARE_CLASS(QWaylandXdgShell)
QT_FORWARD_DECLARE_CLASS(QWaylandXdgSurface)
QT_FORWARD_DECLARE_CLASS(QWaylandXdgToplevel)
QT_FORWARD_DECLARE_CLASS(QWaylandXdgPopup)
-typedef QWaylandXdgShell WaylandXdgShell;
-typedef QWaylandXdgSurface WaylandXdgSurface;
-
-#else
-QT_FORWARD_DECLARE_CLASS(QWaylandXdgShellV5)
-QT_FORWARD_DECLARE_CLASS(QWaylandXdgSurfaceV5)
-typedef QWaylandXdgShellV5 WaylandXdgShell;
-typedef QWaylandXdgSurfaceV5 WaylandXdgSurface;
-
-#endif
QT_BEGIN_NAMESPACE_AM
@@ -86,12 +74,9 @@ class WindowSurfaceQuickItem;
// A WindowSurface object exists for every Wayland surface created in the Wayland server.
// Not every WindowSurface maybe an application's Window though - those that are, are available
// through the WindowManager model.
-
-// On Qt 5.11: we support wl-shell and xdg-shell-v5 shell integration extensions. There's no xdg-shell yet
-// in qtwayland
//
-// On Qt 5.12: we support wl-shell and xdg-shell shell integration extensions. Both wl-shell and xdg-shell-v5
-// are deprecated and additionally xdg-shell-v5 is partially broken in qtwayland.
+// we support wl-shell and xdg-shell shell integration extensions. Both wl-shell and xdg-shell-v5
+// are deprecated and additionally xdg-shell-v5 is partially broken in qtwayland.
//
// In any case, wl-shell doesn't provide all the features needed by appman, so clients using it will never work
// perfectly.
@@ -128,11 +113,9 @@ private:
WaylandCompositor *m_compositor;
QWaylandWlShellSurface *m_wlSurface = nullptr;
- WaylandXdgSurface *m_xdgSurface = nullptr;
-#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
+ QWaylandXdgSurface *m_xdgSurface = nullptr;
QWaylandXdgToplevel *m_topLevel = nullptr;
QWaylandXdgPopup *m_popup = nullptr;
-#endif
friend class WaylandCompositor;
};
@@ -154,15 +137,13 @@ signals:
protected:
void doCreateSurface(QWaylandClient *client, uint id, int version);
void createWlSurface(QWaylandSurface *surface, const QWaylandResource &resource);
- void onXdgSurfaceCreated(WaylandXdgSurface *xdgSurface);
-#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
+ void onXdgSurfaceCreated(QWaylandXdgSurface *xdgSurface);
void onTopLevelCreated(QWaylandXdgToplevel *toplevel, QWaylandXdgSurface *xdgSurface);
void onPopupCreated(QWaylandXdgPopup *popup, QWaylandXdgSurface *xdgSurface);
-#endif
void onXdgPongReceived(uint serial);
QWaylandWlShell *m_wlShell;
- WaylandXdgShell *m_xdgShell;
+ QWaylandXdgShell *m_xdgShell;
QVector<QWaylandOutput *> m_outputs;
WaylandQtAMServerExtension *m_amExtension;
QWaylandTextInputManager *m_textInputManager;
diff --git a/src/window-lib/waylandqtamserverextension.cpp b/src/window-lib/waylandqtamserverextension.cpp
index cdce4e1e..a383217a 100644
--- a/src/window-lib/waylandqtamserverextension.cpp
+++ b/src/window-lib/waylandqtamserverextension.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/window-lib/waylandqtamserverextension_p.h b/src/window-lib/waylandqtamserverextension_p.h
index 4ef11d0e..a5756295 100644
--- a/src/window-lib/waylandqtamserverextension_p.h
+++ b/src/window-lib/waylandqtamserverextension_p.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/window-lib/waylandwindow.cpp b/src/window-lib/waylandwindow.cpp
index 6382bc05..13ca090d 100644
--- a/src/window-lib/waylandwindow.cpp
+++ b/src/window-lib/waylandwindow.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE_AM
bool WaylandWindow::m_watchdogEnabled = true;
-WaylandWindow::WaylandWindow(AbstractApplication *app, WindowSurface *surf)
+WaylandWindow::WaylandWindow(Application *app, WindowSurface *surf)
: Window(app)
, m_pingTimer(new QTimer(this))
, m_pongTimer(new QTimer(this))
@@ -66,8 +66,6 @@ WaylandWindow::WaylandWindow(AbstractApplication *app, WindowSurface *surf)
if (surf) {
connect(surf, &WindowSurface::pong,
this, &WaylandWindow::pongReceived);
- connect(m_surface, &WindowSurface::redraw,
- this, &WaylandWindow::frameUpdated);
connect(m_surface, &QWaylandSurface::hasContentChanged, this, &WaylandWindow::onContentStateChanged);
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
connect(m_surface, &QWaylandSurface::sizeChanged, this, &Window::sizeChanged);
diff --git a/src/window-lib/waylandwindow.h b/src/window-lib/waylandwindow.h
index 33fbea13..1373d338 100644
--- a/src/window-lib/waylandwindow.h
+++ b/src/window-lib/waylandwindow.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -59,7 +59,7 @@ class WaylandWindow : public Window
Q_PROPERTY(QWaylandQuickSurface* waylandSurface READ waylandSurface NOTIFY waylandSurfaceChanged)
public:
- WaylandWindow(AbstractApplication *app, WindowSurface *surface);
+ WaylandWindow(Application *app, WindowSurface *surface);
bool isInProcess() const override { return false; }
@@ -84,7 +84,6 @@ public:
static bool m_watchdogEnabled;
signals:
- void frameUpdated();
void waylandSurfaceChanged();
private slots:
diff --git a/src/window-lib/window-lib.pro b/src/window-lib/window-lib.pro
index a5a43177..918bbe34 100644
--- a/src/window-lib/window-lib.pro
+++ b/src/window-lib/window-lib.pro
@@ -10,6 +10,7 @@ QT_FOR_PRIVATE *= \
appman_common-private \
appman_application-private \
appman_manager-private \
+ appman_monitor-private \
CONFIG *= static internal_module
CONFIG -= create_cmake
@@ -45,7 +46,6 @@ multi-process:!headless {
windowmanager_p.h \
touchemulation.h \
-
!headless:SOURCES += \
window.cpp \
windowitem.cpp \
diff --git a/src/window-lib/window.cpp b/src/window-lib/window.cpp
index 13bc7053..6598b8b4 100644
--- a/src/window-lib/window.cpp
+++ b/src/window-lib/window.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -185,7 +185,7 @@
*/
QT_BEGIN_NAMESPACE_AM
-Window::Window(AbstractApplication *app)
+Window::Window(Application *app)
: QObject()
, m_application(app)
{
@@ -196,7 +196,7 @@ Window::~Window()
emit _windowDestroyed();
}
-AbstractApplication *Window::application() const
+Application *Window::application() const
{
return m_application;
}
diff --git a/src/window-lib/window.h b/src/window-lib/window.h
index e2981cea..e41058fe 100644
--- a/src/window-lib/window.h
+++ b/src/window-lib/window.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -66,7 +66,7 @@ class Window : public QObject
Q_PROPERTY(QSize size READ size NOTIFY sizeChanged)
Q_PROPERTY(ContentState contentState READ contentState NOTIFY contentStateChanged)
- Q_PROPERTY(AbstractApplication* application READ application CONSTANT)
+ Q_PROPERTY(Application* application READ application CONSTANT)
Q_PROPERTY(bool popup READ isPopup CONSTANT)
Q_PROPERTY(QPoint requestedPopupPosition READ requestedPopupPosition NOTIFY requestedPopupPositionChanged)
@@ -79,11 +79,11 @@ public:
};
Q_ENUM(ContentState)
- Window(AbstractApplication *app);
+ Window(Application *app);
virtual ~Window();
virtual bool isInProcess() const = 0;
- virtual AbstractApplication *application() const;
+ virtual Application *application() const;
// Controls how many items (which are views from a model-view perspective) are currently rendering this window
void registerItem(WindowItem *item);
@@ -125,7 +125,7 @@ signals:
void _windowDestroyed();
protected:
- QPointer<AbstractApplication> m_application;
+ QPointer<Application> m_application;
QSet<WindowItem*> m_items;
WindowItem *m_primaryItem{nullptr};
diff --git a/src/window-lib/windowitem.cpp b/src/window-lib/windowitem.cpp
index 5a00bceb..7fb17f69 100644
--- a/src/window-lib/windowitem.cpp
+++ b/src/window-lib/windowitem.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/window-lib/windowitem.h b/src/window-lib/windowitem.h
index 45bf9c71..4bc4b39b 100644
--- a/src/window-lib/windowitem.h
+++ b/src/window-lib/windowitem.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/src/window-lib/windowmanager.cpp b/src/window-lib/windowmanager.cpp
index ea9a3027..4bb3d3b5 100644
--- a/src/window-lib/windowmanager.cpp
+++ b/src/window-lib/windowmanager.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -334,7 +334,7 @@ void WindowManager::setSlowAnimations(bool slowAnimations)
RuntimeFactory::instance()->setSlowAnimations(d->slowAnimations);
// Update already running applications
- for (AbstractApplication *application : ApplicationManager::instance()->applications()) {
+ for (Application *application : ApplicationManager::instance()->applications()) {
auto runtime = application->currentRuntime();
if (runtime)
runtime->setSlowAnimations(d->slowAnimations);
@@ -475,12 +475,53 @@ QVariantMap WindowManager::get(int index) const
}
/*!
+ \qmlmethod WindowObject WindowManager::window(int index)
+
+ Returns the \l{WindowObject}{window} corresponding to the given \a index in the
+ model, or \c null if the index is invalid.
+
+ \note The object ownership of the returned Window object stays with the application-manager.
+ If you want to store this pointer, you can use the WindowManager's QAbstractListModel
+ signals or the windowAboutToBeRemoved signal to get notified if the object is about
+ to be deleted on the C++ side.
+*/
+Window *WindowManager::window(int index) const
+{
+ if (index < 0 || index >= count()) {
+ qCWarning(LogSystem) << "WindowManager::window(index): invalid index:" << index;
+ return nullptr;
+ }
+ return d->windowsInModel.at(index);
+}
+
+/*!
+ \qmlmethod list<WindowObject> WindowManager::windowsOfApplication(string applicationId)
+
+ Returns a list of \l{WindowObject}{windows} belonging to the given \a applicationId in the
+ model, or an empty list if the applicationId is invalid.
+
+ \note The object ownership of the returned Window objects stays with the application-manager.
+ If you want to store these pointers, you can use the WindowManager's QAbstractListModel
+ signals or the windowAboutToBeRemoved signal to get notified if the objects are about
+ to be deleted on the C++ side.
+*/
+QList<QObject *> WindowManager::windowsOfApplication(const QString &id) const
+{
+ QList<QObject *> result;
+ for (Window *window : d->windowsInModel) {
+ if (window->application() && window->application()->id() == id)
+ result << window;
+ }
+ return result;
+}
+
+/*!
\qmlmethod int WindowManager::indexOfWindow(WindowObject window)
Returns the index of the \a window within the WindowManager model, or \c -1 if the window item is
not a managed window.
*/
-int WindowManager::indexOfWindow(Window *window)
+int WindowManager::indexOfWindow(Window *window) const
{
return d->windowsInModel.indexOf(window);
}
@@ -534,6 +575,7 @@ QObject *WindowManager::addExtension(QQmlComponent *component) const
return extension;
#else
+ Q_UNUSED(component)
return nullptr;
#endif
}
@@ -654,7 +696,7 @@ void WindowManager::inProcessSurfaceItemCreated(QSharedPointer<InProcessSurfaceI
qCCritical(LogSystem) << "This function must be called by a signal of Runtime!";
return;
}
- AbstractApplication *app = rt->application() ? rt->application()->nonAliased() : nullptr;
+ Application *app = rt->application() ? rt->application()->nonAliased() : nullptr;
if (!app) {
qCCritical(LogSystem) << "This function must be called by a signal of Runtime which actually has an application attached!";
return;
@@ -730,7 +772,7 @@ void WindowManager::waylandSurfaceCreated(QWaylandSurface *surface)
void WindowManager::waylandSurfaceMapped(WindowSurface *surface)
{
qint64 processId = surface->processId();
- AbstractApplication *app = ApplicationManager::instance()->fromProcessId(processId);
+ Application *app = ApplicationManager::instance()->fromProcessId(processId);
if (!app && ApplicationManager::instance()->securityChecksEnabled()) {
qCCritical(LogGraphics) << "SECURITY ALERT: an unknown application with pid" << processId
@@ -888,8 +930,8 @@ bool WindowManager::makeScreenshot(const QString &filename, const QString &selec
// app without System-UI
// filter out alias and apps not matching appId (if set)
- QVector<AbstractApplication *> apps = ApplicationManager::instance()->applications();
- auto it = std::remove_if(apps.begin(), apps.end(), [appId](AbstractApplication *app) {
+ QVector<Application *> apps = ApplicationManager::instance()->applications();
+ auto it = std::remove_if(apps.begin(), apps.end(), [appId](Application *app) {
return app->isAlias() || (!appId.isEmpty() && (appId != app->id()));
});
apps.erase(it, apps.end());
@@ -975,7 +1017,7 @@ int WindowManagerPrivate::findWindowByWaylandSurface(QWaylandSurface *waylandSur
return -1;
}
-QString WindowManagerPrivate::applicationId(AbstractApplication *app, WindowSurface *windowSurface)
+QString WindowManagerPrivate::applicationId(Application *app, WindowSurface *windowSurface)
{
if (app)
return app->id();
diff --git a/src/window-lib/windowmanager.h b/src/window-lib/windowmanager.h
index 194865fe..6e6d5982 100644
--- a/src/window-lib/windowmanager.h
+++ b/src/window-lib/windowmanager.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -98,8 +98,9 @@ public:
Q_INVOKABLE int count() const;
Q_INVOKABLE QVariantMap get(int index) const;
-
- Q_INVOKABLE int indexOfWindow(Window *window);
+ Q_INVOKABLE Window *window(int index) const;
+ Q_INVOKABLE QList<QObject *> windowsOfApplication(const QString &id) const;
+ Q_INVOKABLE int indexOfWindow(Window *window) const;
Q_INVOKABLE QObject *addExtension(QQmlComponent *component) const;
bool eventFilter(QObject *watched, QEvent *event) override;
@@ -129,8 +130,6 @@ private slots:
public:
Q_SCRIPTABLE bool makeScreenshot(const QString &filename, const QString &selector);
- bool setDBusPolicy(const QVariantMap &yamlFragment);
-
QList<QQuickWindow *> compositorViews() const;
// evil hook to support in-process runtimes
diff --git a/src/window-lib/windowmanager_p.h b/src/window-lib/windowmanager_p.h
index 7195f541..f692e765 100644
--- a/src/window-lib/windowmanager_p.h
+++ b/src/window-lib/windowmanager_p.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -62,7 +62,7 @@ public:
WaylandCompositor *waylandCompositor = nullptr;
- static QString applicationId(AbstractApplication *app, WindowSurface *windowSurface);
+ static QString applicationId(Application *app, WindowSurface *windowSurface);
#endif
QHash<int, QByteArray> roleNames;
diff --git a/sync.profile b/sync.profile
index 142d3f44..3a6983dd 100644
--- a/sync.profile
+++ b/sync.profile
@@ -8,7 +8,6 @@
"QtAppManSharedMain" => "$basedir/src/shared-main-lib",
"QtAppManMain" => "$basedir/src/main-lib",
"QtAppManWindow" => "$basedir/src/window-lib",
- "QtAppManInstaller" => "$basedir/src/installer-lib",
"QtAppManLauncher" => "$basedir/src/launcher-lib",
"QtAppManPluginInterfaces" => "$basedir/src/plugin-interfaces",
"QtAppManMonitor" => "$basedir/src/monitor-lib",
diff --git a/template-opt/am/config-windows.yaml b/template-opt/am/config-windows.yaml
index 0f1325b7..6af28123 100644
--- a/template-opt/am/config-windows.yaml
+++ b/template-opt/am/config-windows.yaml
@@ -4,15 +4,5 @@ formatType: am-configuration
# installations will go into the standard /opt/am hierarchy
applications:
- installedAppsManifestDir: "c:/cygwin/opt/am/manifests"
- appImageMountDir: "c:/cygwin/opt/am/image-mounts"
- database: "c:/cygwin/opt/am/apps.db"
-
-# simulate an internal and a SD-card installation location
-
-installationLocations:
-- id: "internal-0"
- installationPath: "c:/cygwin/opt/am/apps"
- documentPath: "c:/cygwin/opt/am/docs"
- mountPoint: "c:/cygwin/opt"
- isDefault: true
+ installationDir: "c:/cygwin/opt/am/apps"
+ documentDir: "c:/cygwin/opt/am/docs"
diff --git a/template-opt/am/config.yaml b/template-opt/am/config.yaml
index 94fc9bcb..b6ed82c4 100644
--- a/template-opt/am/config.yaml
+++ b/template-opt/am/config.yaml
@@ -4,20 +4,5 @@ formatType: am-configuration
# installations will go into the standard /opt/am hierarchy
applications:
- installedAppsManifestDir: "/opt/am/manifests"
- appImageMountDir: "/opt/am/image-mounts"
- database: "/opt/am/apps.db"
-
-# simulate an internal and a SD-card installation location
-
-installationLocations:
-- id: "internal-0"
- installationPath: "/opt/am/apps"
- documentPath: "/opt/am/docs"
- mountPoint: "/opt"
- isDefault: true
-
-- id: "removable-0"
- installationPath: "/media/sdcard/apps"
- documentPath: "/media/sdcard/docs"
- mountPoint: "/media/sdcard"
+ installationDir: "/opt/am/apps"
+ documentDir: "/opt/am/docs"
diff --git a/tests/application/application.pro b/tests/application/application.pro
index cc13702e..2bdaf9c5 100644
--- a/tests/application/application.pro
+++ b/tests/application/application.pro
@@ -8,3 +8,6 @@ QT *= \
appman_manager-private \
SOURCES += tst_application.cpp
+
+OTHER_FILES += info.yaml
+RESOURCES += tst_application.qrc
diff --git a/tests/application/icon.png b/tests/application/icon.png
new file mode 100644
index 00000000..909c66db
--- /dev/null
+++ b/tests/application/icon.png
Binary files differ
diff --git a/tests/application/info.yaml b/tests/application/info.yaml
new file mode 100644
index 00000000..08329bb8
--- /dev/null
+++ b/tests/application/info.yaml
@@ -0,0 +1,10 @@
+formatType: am-package
+formatVersion: 1
+---
+id: pkg.test
+name: { en: "Test Package" }
+icon: icon.png
+applications:
+- id: app.test
+ runtime: qml
+ code: info.yaml # just to make the test simpler
diff --git a/tests/application/tst_application.cpp b/tests/application/tst_application.cpp
index 8dbe29af..20ae20ac 100644
--- a/tests/application/tst_application.cpp
+++ b/tests/application/tst_application.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -33,6 +34,8 @@
#include "global.h"
#include "application.h"
#include "applicationinfo.h"
+#include "packageinfo.h"
+#include "package.h"
#include "abstractruntime.h"
QT_USE_NAMESPACE_AM
@@ -48,19 +51,19 @@ public:
void setSlowAnimations(bool) override {}
- qint64 applicationProcessId() const
+ qint64 applicationProcessId() const override
{
return m_state == Am::Running ? 1 : 0;
}
public slots:
- bool start()
+ bool start() override
{
m_state = Am::Running;
return true;
}
- void stop(bool forceKill)
+ void stop(bool forceKill) override
{
Q_UNUSED(forceKill);
m_state = Am::NotRunning;
@@ -104,7 +107,10 @@ private slots:
// the application no longer holds a reference to it
void tst_Application::runtimeDestroyed()
{
- auto app = new Application(new ApplicationInfo);
+ auto pi = PackageInfo::fromManifest(qL1S(":/info.yaml"));
+ auto pkg = new Package(pi);
+ auto ai = new ApplicationInfo(pi);
+ auto app = new Application(ai, pkg);
auto runtimeManager = new TestRuntimeManager(qSL("foo"), qApp);
auto runtime = runtimeManager->create(nullptr, app);
diff --git a/tests/application/tst_application.qrc b/tests/application/tst_application.qrc
new file mode 100644
index 00000000..a24bcd9a
--- /dev/null
+++ b/tests/application/tst_application.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>info.yaml</file>
+</qresource>
+</RCC>
diff --git a/tests/applicationinfo/tst_applicationinfo.cpp b/tests/applicationinfo/tst_applicationinfo.cpp
index 92f1fe3a..f9739dac 100644
--- a/tests/applicationinfo/tst_applicationinfo.cpp
+++ b/tests/applicationinfo/tst_applicationinfo.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -33,8 +33,8 @@
#include "global.h"
#include "application.h"
#include "applicationinfo.h"
-#include "applicationdatabase.h"
-#include "yamlapplicationscanner.h"
+#include "packageinfo.h"
+#include "yamlpackagescanner.h"
#include "exception.h"
QT_USE_NAMESPACE_AM
@@ -49,7 +49,6 @@ public:
private slots:
void initTestCase();
void cleanupTestCase();
- void database();
void application_data();
void application();
void validApplicationId_data();
@@ -58,7 +57,7 @@ private slots:
void validIcon();
private:
- QVector<AbstractApplicationInfo *> apps;
+ QVector<PackageInfo *> m_pkgs;
};
tst_ApplicationInfo::tst_ApplicationInfo()
@@ -67,100 +66,29 @@ tst_ApplicationInfo::tst_ApplicationInfo()
void tst_ApplicationInfo::initTestCase()
{
- YamlApplicationScanner scanner;
+ YamlPackageScanner scanner;
QDir baseDir(qL1S(AM_TESTDATA_DIR "manifests"));
- const QStringList appDirNames = baseDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
- for (const QString &appDirName : appDirNames) {
- QDir dir = baseDir.absoluteFilePath(appDirName);
+ const QStringList pkgDirNames = baseDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
+ for (const QString &pkgDirName : pkgDirNames) {
+ QDir dir = baseDir.absoluteFilePath(pkgDirName);
try {
- ApplicationInfo *a = scanner.scan(dir.absoluteFilePath(qSL("info.yaml")));
- QVERIFY(a);
- QCOMPARE(appDirName, a->id());
- apps << a;
+ PackageInfo *pi = scanner.scan(dir.absoluteFilePath(qSL("info.yaml")));
+ QVERIFY(pi);
+ QCOMPARE(pkgDirName, pi->id());
+ m_pkgs << pi;
} catch (const std::exception &e) {
QFAIL(e.what());
}
}
- QCOMPARE(apps.size(), 2);
+ QCOMPARE(m_pkgs.size(), 2);
}
void tst_ApplicationInfo::cleanupTestCase()
{
- qDeleteAll(apps);
+ qDeleteAll(m_pkgs);
}
-void tst_ApplicationInfo::database()
-{
- QString tmpDbPath = QDir::temp().absoluteFilePath(qSL("autotest-appdb-%1").arg(qApp->applicationPid()));
-
- QFile::remove(tmpDbPath);
- QVERIFY(!QFile::exists(tmpDbPath));
-
- {
- ApplicationDatabase adb(QDir::tempPath());
- QVERIFY(!adb.isValid());
- }
-
- {
- ApplicationDatabase adb(tmpDbPath);
- QVERIFY(adb.isValid());
-
- try {
- QVector<AbstractApplication *> appsInDb = adb.read();
- QVERIFY(appsInDb.isEmpty());
-
- adb.write(apps);
- qDeleteAll(appsInDb);
- } catch (const Exception &e) {
- QVERIFY2(false, e.what());
- }
- }
-
- QVERIFY(QFileInfo(tmpDbPath).size() > 0);
-
- {
- ApplicationDatabase adb(tmpDbPath);
- QVERIFY(adb.isValid());
-
- try {
- QVector<AbstractApplication *> appsInDb = adb.read();
- QCOMPARE(appsInDb.size(), apps.size());
- qDeleteAll(appsInDb);
- } catch (Exception &e) {
- QVERIFY2(false, e.what());
- }
- }
-
- {
-#if defined(Q_OS_WIN)
- QString nullDb(qSL("\\\\.\\NUL"));
-#else
- QString nullDb(qSL("/dev/zero"));
-#endif
-
- ApplicationDatabase adb(nullDb);
- QVERIFY2(adb.isValid(), qPrintable(adb.errorString()));
-
- try {
- adb.write(apps);
- QVERIFY(false);
- } catch (const Exception &) {
- }
- }
-
- /*{
- ApplicationDatabase adb("/proc/self/sched");
- QVERIFY(adb.isValid());
-
- try {
- // adb.write(apps);
- // QVERIFY(false);
- } catch (Exception &) {
- }
- }*/
-
-}
void tst_ApplicationInfo::application_data()
{
QTest::addColumn<QString>("id");
@@ -175,87 +103,79 @@ void tst_ApplicationInfo::application()
QString name = QString::fromLatin1(AM_TESTDATA_DIR "manifests/%1/info.yaml").arg(id);
- YamlApplicationScanner scanner;
- ApplicationInfo *app;
+ YamlPackageScanner scanner;
+ PackageInfo *pkg;
try {
- app = scanner.scan(name);
- QVERIFY(app);
+ pkg = scanner.scan(name);
+ QVERIFY(pkg);
} catch (const std::exception &e) {
QFAIL(e.what());
}
- QCOMPARE(app->id(), id);
- QCOMPARE(QFileInfo(app->icon()).fileName(), qSL("icon.png"));
- QCOMPARE(app->names().size(), 2);
- QCOMPARE(app->names().value(qSL("en")), qSL("english"));
- QCOMPARE(app->names().value(qSL("de")), qSL("deutsch"));
- QCOMPARE(app->name(qSL("en")), qSL("english"));
+ QCOMPARE(pkg->id(), id);
+ QCOMPARE(QFileInfo(pkg->icon()).fileName(), qSL("icon.png"));
+ QCOMPARE(pkg->names().size(), 2);
+ QCOMPARE(pkg->names().value(qSL("en")), qSL("english"));
+ QCOMPARE(pkg->names().value(qSL("de")), qSL("deutsch"));
+ QCOMPARE(pkg->name(qSL("en")), qSL("english"));
+ QCOMPARE(pkg->isBuiltIn(), false);
+ QCOMPARE(pkg->categories().size(), 2);
+ QVERIFY(pkg->categories().startsWith(qSL("bar")));
+ QVERIFY(pkg->categories().endsWith(qSL("foo")));
+
+ ApplicationInfo *app = pkg->applications().size() == 1 ? pkg->applications().first() : nullptr;
+ QVERIFY(app);
QCOMPARE(QFileInfo(app->codeFilePath()).fileName(), qSL("Test.qml"));
QCOMPARE(app->runtimeName(), qSL("qml"));
QCOMPARE(app->runtimeParameters().size(), 1);
QCOMPARE(app->runtimeParameters().value(qSL("loadDummyData")).toBool(), true);
- QCOMPARE(app->isBuiltIn(), false);
- QCOMPARE(app->supportedMimeTypes().size(), 2);
- QVERIFY(app->supportedMimeTypes().startsWith(qSL("text/plain")));
- QVERIFY(app->supportedMimeTypes().endsWith(qSL("x-scheme-handler/mailto")));
QCOMPARE(app->capabilities().size(), 2);
QVERIFY(app->capabilities().startsWith(qSL("cameraAccess")));
QVERIFY(app->capabilities().endsWith(qSL("locationAccess")));
- QCOMPARE(app->categories().size(), 2);
- QVERIFY(app->categories().startsWith(qSL("bar")));
- QVERIFY(app->categories().endsWith(qSL("foo")));
- delete app;
+ // legacy
+ QCOMPARE(app->supportedMimeTypes().size(), 2);
+ QVERIFY(app->supportedMimeTypes().startsWith(qSL("text/plain")));
+ QVERIFY(app->supportedMimeTypes().endsWith(qSL("x-scheme-handler/mailto")));
+
+ delete pkg;
}
void tst_ApplicationInfo::validApplicationId_data()
{
QTest::addColumn<QString>("appId");
- QTest::addColumn<bool>("isAlias");
QTest::addColumn<bool>("valid");
// passes
- QTest::newRow("normal") << "Test" << false << true;
- QTest::newRow("shortest") << "t" << false << true;
- QTest::newRow("valid-chars") << "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,.';[]{}!#$%^&()-_=+" << false << true;
- QTest::newRow("longest-name") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.test" << false << true;
- QTest::newRow("alias-normal") << "Test@alias" << true << true;
- QTest::newRow("alias-shortest") << "t@a" << true << true;
- QTest::newRow("alias-valid-chars") << "1-2@1-a" << true << true;
- QTest::newRow("alias-longest-part") << "com.012345678901234567890123456789012345678901234567890123456789012.test@012345678901234567890123456789012345678901234567890123456789012" << true << true;
- QTest::newRow("alias-longest-name") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012@test" << true << true;
- QTest::newRow("alias-max-part-cnt") << "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.0.1.2.3.4.5.6.7.8.9.a.0@12" << true << true;
+ QTest::newRow("normal") << "Test" << true;
+ QTest::newRow("shortest") << "t" << true;
+ QTest::newRow("valid-chars") << "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,.';[]{}!#$%^&()-_=+@" << true;
+ QTest::newRow("longest-name") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.test" << true;
// failures
- QTest::newRow("empty") << "" << false << false;
- QTest::newRow("space-only") << " " << false << false;
- QTest::newRow("space-only2") << " " << false << false;
- QTest::newRow("name-too-long") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.xtest" << false << false;
- QTest::newRow("empty-alias") << "test@" << true << false;
- QTest::newRow("invalid-char@") << "t@" << false << false;
- QTest::newRow("invalid-char<") << "t<" << false << false;
- QTest::newRow("invalid-char>") << "t>" << false << false;
- QTest::newRow("invalid-char:") << "t:" << false << false;
- QTest::newRow("invalid-char-quote") << "t\"" << false << false;
- QTest::newRow("invalid-char/") << "t/" << false << false;
- QTest::newRow("invalid-char\\") << "t\\" << false << false;
- QTest::newRow("invalid-char|") << "t|" << false << false;
- QTest::newRow("invalid-char?") << "t?" << false << false;
- QTest::newRow("invalid-char*") << "t*" << false << false;
- QTest::newRow("control-char") << "t\t" << false << false;
- QTest::newRow("unicode-char") << QString::fromUtf8("c.p.t@c\xc3\xb6m") << true << false;
- QTest::newRow("no-alias") << "t" << true << false;
- QTest::newRow("alias-name-too-long") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012@xtest" << true << false;
+ QTest::newRow("empty") << "" << false;
+ QTest::newRow("space-only") << " " << false;
+ QTest::newRow("space-only2") << " " << false;
+ QTest::newRow("name-too-long") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.xtest" << false;
+ QTest::newRow("invalid-char<") << "t<" << false;
+ QTest::newRow("invalid-char>") << "t>" << false;
+ QTest::newRow("invalid-char:") << "t:" << false;
+ QTest::newRow("invalid-char-quote") << "t\"" << false;
+ QTest::newRow("invalid-char/") << "t/" << false;
+ QTest::newRow("invalid-char\\") << "t\\" << false;
+ QTest::newRow("invalid-char|") << "t|" << false;
+ QTest::newRow("invalid-char?") << "t?" << false;
+ QTest::newRow("invalid-char*") << "t*" << false;
+ QTest::newRow("control-char") << "t\t" << false;
}
void tst_ApplicationInfo::validApplicationId()
{
QFETCH(QString, appId);
- QFETCH(bool, isAlias);
QFETCH(bool, valid);
QString errorString;
- bool result = AbstractApplicationInfo::isValidApplicationId(appId, isAlias, &errorString);
+ bool result = PackageInfo::isValidApplicationId(appId, &errorString);
QVERIFY2(valid == result, qPrintable(errorString));
}
@@ -284,7 +204,7 @@ void tst_ApplicationInfo::validIcon()
QFETCH(bool, isValid);
QString errorString;
- bool result = AbstractApplicationInfo::isValidIcon(icon, errorString);
+ bool result = PackageInfo::isValidIcon(icon, &errorString);
QCOMPARE(result, isValid);
}
diff --git a/tests/applicationinstaller/applicationinstaller.pro b/tests/applicationinstaller/applicationinstaller.pro
index 37532e10..b84ffac4 100644
--- a/tests/applicationinstaller/applicationinstaller.pro
+++ b/tests/applicationinstaller/applicationinstaller.pro
@@ -9,6 +9,5 @@ QT *= \
appman_application-private \
appman_package-private \
appman_manager-private \
- appman_installer-private
SOURCES += tst_applicationinstaller.cpp
diff --git a/tests/applicationinstaller/tst_applicationinstaller.cpp b/tests/applicationinstaller/tst_applicationinstaller.cpp
index c187a088..bb73c758 100644
--- a/tests/applicationinstaller/tst_applicationinstaller.cpp
+++ b/tests/applicationinstaller/tst_applicationinstaller.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -32,16 +33,17 @@
#include <functional>
-#include "applicationinstaller.h"
-#include "applicationmanager.h"
-#include "application.h"
+#include "packagemanager.h"
+#include "packagedatabase.h"
+#include "package.h"
+#include "applicationinfo.h"
#include "sudo.h"
#include "utilities.h"
#include "error.h"
-#include "private/package_p.h"
+#include "private/packageutilities_p.h"
#include "runtimefactory.h"
#include "qmlinprocessruntime.h"
-#include "package.h"
+#include "packageutilities.h"
#include "../error-checking.h"
@@ -63,41 +65,41 @@ public:
};
AllowInstallations(Type t)
- : m_oldUnsigned(ApplicationInstaller::instance()->allowInstallationOfUnsignedPackages())
- , m_oldDevMode(ApplicationInstaller::instance()->developmentMode())
+ : m_oldUnsigned(PackageManager::instance()->allowInstallationOfUnsignedPackages())
+ , m_oldDevMode(PackageManager::instance()->developmentMode())
{
switch (t) {
case AllowUnsinged:
- ApplicationInstaller::instance()->setAllowInstallationOfUnsignedPackages(true);
- ApplicationInstaller::instance()->setDevelopmentMode(false);
+ PackageManager::instance()->setAllowInstallationOfUnsignedPackages(true);
+ PackageManager::instance()->setDevelopmentMode(false);
break;
case RequireDevSigned:
- ApplicationInstaller::instance()->setAllowInstallationOfUnsignedPackages(false);
- ApplicationInstaller::instance()->setDevelopmentMode(true);
+ PackageManager::instance()->setAllowInstallationOfUnsignedPackages(false);
+ PackageManager::instance()->setDevelopmentMode(true);
break;
case RequireStoreSigned:
- ApplicationInstaller::instance()->setAllowInstallationOfUnsignedPackages(false);
- ApplicationInstaller::instance()->setDevelopmentMode(false);
+ PackageManager::instance()->setAllowInstallationOfUnsignedPackages(false);
+ PackageManager::instance()->setDevelopmentMode(false);
break;
}
}
~AllowInstallations()
{
- ApplicationInstaller::instance()->setAllowInstallationOfUnsignedPackages(m_oldUnsigned);
- ApplicationInstaller::instance()->setDevelopmentMode(m_oldDevMode);
+ PackageManager::instance()->setAllowInstallationOfUnsignedPackages(m_oldUnsigned);
+ PackageManager::instance()->setDevelopmentMode(m_oldDevMode);
}
private:
bool m_oldUnsigned;
bool m_oldDevMode;
};
-class tst_ApplicationInstaller : public QObject
+class tst_PackageManager : public QObject
{
Q_OBJECT
public:
- tst_ApplicationInstaller(QObject *parent = nullptr);
- ~tst_ApplicationInstaller();
+ tst_PackageManager(QObject *parent = nullptr);
+ ~tst_PackageManager();
private slots:
void initTestCase();
@@ -108,8 +110,6 @@ private slots:
//TODO: test AI::cleanupBrokenInstallations() before calling cleanup() the first time!
- void installationLocations();
-
void packageInstallation_data();
void packageInstallation();
@@ -129,11 +129,8 @@ private slots:
public:
enum PathLocation {
- Manifests = 0,
Internal0,
Documents0,
- Internal1,
- Documents1,
PathLocationCount
};
@@ -148,11 +145,8 @@ private:
{
QString base;
switch (pathLocation) {
- case Manifests: base = "manifests"; break;
- case Internal0: base = "internal-0"; break;
- case Documents0: base = "documents-0"; break;
- case Internal1: base = "internal-1"; break;
- case Documents1: base = "documents-1"; break;
+ case Internal0: base = qSL("internal"); break;
+ case Documents0: base = qSL("documents"); break;
default: break;
}
@@ -194,8 +188,7 @@ private:
QTemporaryDir m_workDir;
QString m_hardwareId;
- QVector<InstallationLocation> m_installationLocations;
- ApplicationInstaller *m_ai = nullptr;
+ PackageManager *m_pm = nullptr;
QSignalSpy *m_startedSpy = nullptr;
QSignalSpy *m_requestingInstallationAcknowledgeSpy = nullptr;
QSignalSpy *m_blockingUntilInstallationAcknowledgeSpy = nullptr;
@@ -205,11 +198,11 @@ private:
};
-tst_ApplicationInstaller::tst_ApplicationInstaller(QObject *parent)
+tst_PackageManager::tst_PackageManager(QObject *parent)
: QObject(parent)
{ }
-tst_ApplicationInstaller::~tst_ApplicationInstaller()
+tst_PackageManager::~tst_PackageManager()
{
if (m_workDir.isValid()) {
if (m_sudo)
@@ -225,79 +218,80 @@ tst_ApplicationInstaller::~tst_ApplicationInstaller()
delete m_requestingInstallationAcknowledgeSpy;
delete m_startedSpy;
- delete m_ai;
+ delete m_pm;
}
-void tst_ApplicationInstaller::initTestCase()
+void tst_PackageManager::initTestCase()
{
if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists())
QSKIP("No test packages available in the data/ directory");
bool verbose = qEnvironmentVariableIsSet("VERBOSE_TEST");
if (!verbose)
- QLoggingCategory::setFilterRules("am.installer.debug=false");
+ QLoggingCategory::setFilterRules(qSL("am.installer.debug=false"));
qInfo() << "Verbose mode is" << (verbose ? "on" : "off") << "(changed by (un)setting $VERBOSE_TEST)";
spyTimeout *= timeoutFactor();
- QVERIFY(Package::checkCorrectLocale());
+ QVERIFY(PackageUtilities::checkCorrectLocale());
QVERIFY2(startedSudoServer, qPrintable(sudoServerError));
m_sudo = SudoClient::instance();
QVERIFY(m_sudo);
m_fakeSudo = m_sudo->isFallbackImplementation();
- // we need a (dummy) ApplicationManager for the installer, since the installer will
- // notify the manager during installations
- QVERIFY(ApplicationManager::createInstance(true));
-
// create a temporary dir (plus sub-dirs) for everything created by this test run
-
QVERIFY(m_workDir.isValid());
// make sure we have a valid hardware-id
- m_hardwareId = "foobar";
+ m_hardwareId = qSL("foobar");
for (int i = 0; i < PathLocationCount; ++i)
QVERIFY(QDir().mkdir(pathTo(PathLocation(i))));
- // define some installation locations for testing
-
- QVariantList iloc = QVariantList {
- QVariantMap {
- { "isDefault", true },
- { "id", "internal-0" },
- { "installationPath", pathTo(Internal0) },
- { "documentPath", pathTo(Documents0) }
- },
- QVariantMap {
- { "id", "internal-1" },
- { "installationPath", pathTo(Internal1) },
- { "documentPath", pathTo(Documents1) },
- }
- };
-
- m_installationLocations = InstallationLocation::parseInstallationLocations(iloc, m_hardwareId);
-
- QCOMPARE(m_installationLocations.size(), 2);
-
- // finally, instantiate the ApplicationInstaller and a bunch of signal-spies for its signals
-
- QString installerError;
- m_ai = ApplicationInstaller::createInstance(m_installationLocations, pathTo(Manifests), m_hardwareId, &installerError);
- QVERIFY2(m_ai, qPrintable(installerError));
+ // finally, instantiate the PackageManager and a bunch of signal-spies for its signals
+ try {
+ PackageDatabase *pdb = new PackageDatabase(QStringList(), pathTo(Internal0));
+ m_pm = PackageManager::createInstance(pdb, pathTo(Documents0));
+ m_pm->setHardwareId(m_hardwareId);
+
+ // simulate the ApplicationManager stopping blocked applications
+ connect(&m_pm->internalSignals, &PackageManagerInternalSignals::registerApplication,
+ this, [this](ApplicationInfo *ai, Package *package) {
+ connect(package, &Package::blockedChanged, this, [ai, package](bool blocked) {
+ if (package->info()->applications().contains(ai) && blocked)
+ package->applicationStoppedDueToBlock(ai->id());
+ });
+ });
+ } catch (const Exception &e) {
+ QVERIFY2(false, e.what());
+ }
- m_startedSpy = new QSignalSpy(m_ai, &ApplicationInstaller::taskStarted);
- m_requestingInstallationAcknowledgeSpy = new QSignalSpy(m_ai, &ApplicationInstaller::taskRequestingInstallationAcknowledge);
- m_blockingUntilInstallationAcknowledgeSpy = new QSignalSpy(m_ai, &ApplicationInstaller::taskBlockingUntilInstallationAcknowledge);
- m_progressSpy = new QSignalSpy(m_ai, &ApplicationInstaller::taskProgressChanged);
- m_finishedSpy = new QSignalSpy(m_ai, &ApplicationInstaller::taskFinished);
- m_failedSpy = new QSignalSpy(m_ai, &ApplicationInstaller::taskFailed);
+ const QVariantMap iloc = m_pm->installationLocation();
+ QCOMPARE(iloc.size(), 3);
+ QCOMPARE(iloc.value(qSL("path")).toString(), pathTo(Internal0));
+ QVERIFY(iloc.value(qSL("deviceSize")).toLongLong() > 0);
+ QVERIFY(iloc.value(qSL("deviceFree")).toLongLong() > 0);
+ QVERIFY(iloc.value(qSL("deviceFree")).toLongLong() < iloc.value(qSL("deviceSize")).toLongLong());
+
+ const QVariantMap dloc = m_pm->documentLocation();
+ QCOMPARE(dloc.size(), 3);
+ QCOMPARE(dloc.value(qSL("path")).toString(), pathTo(Documents0));
+ QVERIFY(dloc.value(qSL("deviceSize")).toLongLong() > 0);
+ QVERIFY(dloc.value(qSL("deviceFree")).toLongLong() > 0);
+ QVERIFY(dloc.value(qSL("deviceFree")).toLongLong() < dloc.value(qSL("deviceSize")).toLongLong());
+
+ m_startedSpy = new QSignalSpy(m_pm, &PackageManager::taskStarted);
+ m_requestingInstallationAcknowledgeSpy = new QSignalSpy(m_pm, &PackageManager::taskRequestingInstallationAcknowledge);
+ m_blockingUntilInstallationAcknowledgeSpy = new QSignalSpy(m_pm, &PackageManager::taskBlockingUntilInstallationAcknowledge);
+ m_progressSpy = new QSignalSpy(m_pm, &PackageManager::taskProgressChanged);
+ m_finishedSpy = new QSignalSpy(m_pm, &PackageManager::taskFinished);
+ m_failedSpy = new QSignalSpy(m_pm, &PackageManager::taskFailed);
// crypto stuff - we need to load the root CA and developer CA certificates
- QFile devcaFile(AM_TESTDATA_DIR "certificates/devca.crt");
- QFile storecaFile(AM_TESTDATA_DIR "certificates/store.crt");
- QFile caFile(AM_TESTDATA_DIR "certificates/ca.crt");
+ QFile devcaFile(qL1S(AM_TESTDATA_DIR "certificates/devca.crt"));
+ QFile storecaFile(qL1S(AM_TESTDATA_DIR "certificates/store.crt"));
+ QFile caFile(qL1S(AM_TESTDATA_DIR "certificates/ca.crt"));
QVERIFY2(devcaFile.open(QIODevice::ReadOnly), qPrintable(devcaFile.errorString()));
QVERIFY2(storecaFile.open(QIODevice::ReadOnly), qPrintable(storecaFile.errorString()));
QVERIFY2(caFile.open(QIODevice::ReadOnly), qPrintable(caFile.errorString()));
@@ -306,24 +300,24 @@ void tst_ApplicationInstaller::initTestCase()
chainOfTrust << devcaFile.readAll() << caFile.readAll();
QVERIFY(!chainOfTrust.at(0).isEmpty());
QVERIFY(!chainOfTrust.at(1).isEmpty());
- m_ai->setCACertificates(chainOfTrust);
+ m_pm->setCACertificates(chainOfTrust);
// we do not require valid store signatures for this test run
- m_ai->setDevelopmentMode(true);
+ m_pm->setDevelopmentMode(true);
// make sure we have a valid runtime available. The important part is
// that we have a runtime called "native" - the functionality does not matter.
RuntimeFactory::instance()->registerRuntime(new QmlInProcessRuntimeManager(qSL("native")));
}
-void tst_ApplicationInstaller::cleanupTestCase()
+void tst_PackageManager::cleanupTestCase()
{
- // the real cleanup happens in ~tst_ApplicationInstaller, since we also need
+ // the real cleanup happens in ~tst_PackageManager, since we also need
// to call this cleanup from the crash handler
}
-void tst_ApplicationInstaller::init()
+void tst_PackageManager::init()
{
// start with a fresh App1 dir on each test run
@@ -331,13 +325,13 @@ void tst_ApplicationInstaller::init()
QVERIFY(QDir().mkdir(pathTo(Internal0)));
}
-void tst_ApplicationInstaller::cleanup()
+void tst_PackageManager::cleanup()
{
// this helps with reducing the amount of cleanup work required
// at the end of each test
try {
- m_ai->cleanupBrokenInstallations();
+ m_pm->cleanupBrokenInstallations();
} catch (const Exception &e) {
QFAIL(e.what());
}
@@ -346,47 +340,10 @@ void tst_ApplicationInstaller::cleanup()
recursiveOperation(pathTo(Internal0), safeRemove);
}
-void tst_ApplicationInstaller::installationLocations()
-{
- QVERIFY(!InstallationLocation().isValid());
-
- const QVector<InstallationLocation> loclist = m_ai->installationLocations();
-
- QCOMPARE(loclist.size(), m_installationLocations.size());
- for (const InstallationLocation &loc : loclist)
- QVERIFY(m_installationLocations.contains(loc));
-
- QVector<InstallationLocation> locationList = InstallationLocation::parseInstallationLocations(QVariantList {
- QVariantMap {
- { "id", "internal-0" },
- { "installationPath", QDir::tempPath() },
- { "documentPath", QDir::tempPath() },
- { "isDefault", true }
- },
- }, m_hardwareId);
- QCOMPARE(locationList.size(), 1);
- InstallationLocation &tmp = locationList.first();
- QVariantMap map = tmp.toVariantMap();
- QVERIFY(!map.isEmpty());
-
- QCOMPARE(map.value("id").toString(), tmp.id());
- QCOMPARE(map.value("index").toInt(), tmp.index());
- QCOMPARE(map.value("installationPath").toString(), tmp.installationPath());
- QCOMPARE(map.value("documentPath").toString(), tmp.documentPath());
- QCOMPARE(map.value("isDefault").toBool(), tmp.isDefault());
- QVERIFY(map.value("installationDeviceSize").toLongLong() > 0);
- QVERIFY(map.value("installationDeviceFree").toLongLong() > 0);
- QVERIFY(map.value("documentDeviceSize").toLongLong() > 0);
- QVERIFY(map.value("documentDeviceFree").toLongLong() > 0);
-}
-
-
-void tst_ApplicationInstaller::packageInstallation_data()
+void tst_PackageManager::packageInstallation_data()
{
QTest::addColumn<QString>("packageName");
- QTest::addColumn<QString>("installationLocationId");
QTest::addColumn<QString>("updatePackageName");
- QTest::addColumn<QString>("updateInstallationLocationId");
QTest::addColumn<bool>("devSigned");
QTest::addColumn<bool>("storeSigned");
QTest::addColumn<bool>("expectedSuccess");
@@ -410,73 +367,65 @@ void tst_ApplicationInstaller::packageInstallation_data()
};
QTest::newRow("normal") \
- << "test.appkg" << "internal-0" << "test-update.appkg" << "internal-0"
+ << "test.appkg" << "test-update.appkg"
<< false << false << true << true << nomd<< "";
QTest::newRow("no-dev-signed") \
- << "test.appkg" << "internal-0" << "" << ""
+ << "test.appkg" << ""
<< true << false << false << false << nomd << "cannot install unsigned packages";
QTest::newRow("dev-signed") \
- << "test-dev-signed.appkg" << "internal-0" << "test-update-dev-signed.appkg" << "internal-0"
+ << "test-dev-signed.appkg" << "test-update-dev-signed.appkg"
<< true << false << true << true << nomd << "";
QTest::newRow("no-store-signed") \
- << "test.appkg" << "internal-0" << "" << ""
+ << "test.appkg" << ""
<< false << true << false << false << nomd << "cannot install unsigned packages";
QTest::newRow("no-store-but-dev-signed") \
- << "test-dev-signed.appkg" << "internal-0" << "" << ""
+ << "test-dev-signed.appkg" << ""
<< false << true << false << false << nomd << "cannot install development packages on consumer devices";
QTest::newRow("store-signed") \
- << "test-store-signed.appkg" << "internal-0" << "" << ""
+ << "test-store-signed.appkg" << ""
<< false << true << true << false << nomd << "";
QTest::newRow("extra-metadata") \
- << "test-extra.appkg" << "internal-0" << "" << ""
+ << "test-extra.appkg" << ""
<< false << false << true << false << extramd << "";
QTest::newRow("extra-metadata-dev-signed") \
- << "test-extra-dev-signed.appkg" << "internal-0" << "" << ""
+ << "test-extra-dev-signed.appkg" << ""
<< true << false << true << false << extramd << "";
- QTest::newRow("update-to-different-location") \
- << "test.appkg" << "internal-0" << "test-update.appkg" << "internal-1"
- << false << false << true << false << nomd << "the application com.pelagicore.test cannot be installed to internal-1, since it is already installed to internal-0";
- QTest::newRow("invalid-location") \
- << "test.appkg" << "internal-42" << "" << ""
- << false << false << false << false << nomd << "invalid installation location";
QTest::newRow("invalid-file-order") \
- << "test-invalid-file-order.appkg" << "internal-0" << "" << ""
- << false << false << false << false << nomd << "The application icon (as stated in info.yaml) must be the second file in the package. Expected 'icon.png', got 'test'";
+ << "test-invalid-file-order.appkg" << ""
+ << false << false << false << false << nomd << "The package icon (as stated in info.yaml) must be the second file in the package. Expected 'icon.png', got 'test'";
QTest::newRow("invalid-header-format") \
- << "test-invalid-header-formatversion.appkg" << "internal-0" << "" << ""
- << false << false << false << false << nomd << "metadata has an invalid format specification: wrong formatVersion header: expected 1, got 2";
+ << "test-invalid-header-formatversion.appkg" << ""
+ << false << false << false << false << nomd << "metadata has an invalid format specification: wrong header: expected am-package-header version 2, got am-package-header version 0";
QTest::newRow("invalid-header-diskspaceused") \
- << "test-invalid-header-diskspaceused.appkg" << "internal-0" << "" << ""
+ << "test-invalid-header-diskspaceused.appkg" << ""
<< false << false << false << false << nomd << "metadata has an invalid diskSpaceUsed field (0)";
QTest::newRow("invalid-header-id") \
- << "test-invalid-header-id.appkg" << "internal-0" << "" << ""
- << false << false << false << false << nomd << "metadata has an invalid applicationId field (:invalid)";
+ << "test-invalid-header-id.appkg" << ""
+ << false << false << false << false << nomd << "metadata has an invalid packageId field (:invalid)";
QTest::newRow("non-matching-header-id") \
- << "test-non-matching-header-id.appkg" << "internal-0" << "" << ""
- << false << false << false << false << nomd << "the application identifiers in --PACKAGE-HEADER--' and info.yaml do not match";
+ << "test-non-matching-header-id.appkg" << ""
+ << false << false << false << false << nomd << "the package identifiers in --PACKAGE-HEADER--' and info.yaml do not match";
QTest::newRow("tampered-extra-signed-header") \
- << "test-tampered-extra-signed-header.appkg" << "internal-0" << "" << ""
+ << "test-tampered-extra-signed-header.appkg" << ""
<< false << false << false << false << nomd << "~package digest mismatch.*";
QTest::newRow("invalid-info.yaml") \
- << "test-invalid-info.appkg" << "internal-0" << "" << ""
- << false << false << false << false << nomd << "~.*YAML parse error at line \\d+, column \\d+: did not find expected key";
+ << "test-invalid-info.appkg" << ""
+ << false << false << false << false << nomd << "~.*did not find expected key.*";
QTest::newRow("invalid-info.yaml-id") \
- << "test-invalid-info-id.appkg" << "internal-0" << "" << ""
- << false << false << false << false << nomd << "~.*the identifier \\(:invalid\\) is not a valid application-id: must consist of printable ASCII characters only, except any of .*";
+ << "test-invalid-info-id.appkg" << ""
+ << false << false << false << false << nomd << "~.*the identifier \\(:invalid\\) is not a valid package-id: must consist of printable ASCII characters only, except any of .*";
QTest::newRow("invalid-footer-signature") \
- << "test-invalid-footer-signature.appkg" << "internal-0" << "" << ""
+ << "test-invalid-footer-signature.appkg" << ""
<< true << false << false << false << nomd << "could not verify the package's developer signature";
}
// this test function is a bit of a kitchen sink, but the basic boiler plate
// code of testing the results of an installation is the biggest part and it
// is always the same.
-void tst_ApplicationInstaller::packageInstallation()
+void tst_PackageManager::packageInstallation()
{
QFETCH(QString, packageName);
- QFETCH(QString, installationLocationId);
QFETCH(QString, updatePackageName);
- QFETCH(QString, updateInstallationLocationId);
QFETCH(bool, devSigned);
QFETCH(bool, storeSigned);
QFETCH(bool, expectedSuccess);
@@ -484,6 +433,9 @@ void tst_ApplicationInstaller::packageInstallation()
QFETCH(QVariantMap, extraMetaData);
QFETCH(QString, errorString);
+ QString installationDir = m_pm->installationLocation().value(qSL("path")).toString();
+ QString documentDir = m_pm->documentLocation().value(qSL("path")).toString();
+
AllowInstallations allow(storeSigned ? AllowInstallations::RequireStoreSigned
: (devSigned ? AllowInstallations::RequireDevSigned
: AllowInstallations::AllowUnsinged));
@@ -491,8 +443,6 @@ void tst_ApplicationInstaller::packageInstallation()
int lastPass = (updatePackageName.isEmpty() ? 1 : 2);
// pass 1 is the installation / pass 2 is the update (if needed)
for (int pass = 1; pass <= lastPass; ++pass) {
- const InstallationLocation &il = m_ai->installationLocationFromId(pass == 1 ? installationLocationId : updateInstallationLocationId);
-
// this makes the results a bit ugly to look at, but it helps with debugging a lot
if (pass > 1)
qInfo("Pass %d", pass);
@@ -500,9 +450,9 @@ void tst_ApplicationInstaller::packageInstallation()
// install (or update) the package
QUrl url = QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/" + (pass == 1 ? packageName : updatePackageName));
- QString taskId = m_ai->startPackageInstallation(il.id(), url);
+ QString taskId = m_pm->startPackageInstallation(url);
QVERIFY(!taskId.isEmpty());
- m_ai->acknowledgePackageInstallation(taskId);
+ m_pm->acknowledgePackageInstallation(taskId);
// check received signals...
@@ -524,16 +474,19 @@ void tst_ApplicationInstaller::packageInstallation()
// check files
- QVERIFY(QFile::exists(pathTo(Manifests, "com.pelagicore.test/installation-report.yaml")));
- QVERIFY(QDir(pathTo(il.documentPath() + "/com.pelagicore.test")).exists());
+ //TODO: remove system((QString::fromUtf8("find ") + m_workDir.path()).toLocal8Bit().constData());
- QString fileCheckPath = il.installationPath() + "/com.pelagicore.test";
+ QVERIFY(QFile::exists(installationDir + qSL("/com.pelagicore.test/.installation-report.yaml")));
+ QVERIFY(QDir(documentDir + qSL("/com.pelagicore.test")).exists());
+
+ QString fileCheckPath = installationDir + "/com.pelagicore.test";
// now check the installed files
QStringList files = QDir(fileCheckPath).entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
files.sort();
- QVERIFY2(files == QStringList({ "icon.png", "info.yaml", "test", QString::fromUtf8("t\xc3\xa4st") }), qPrintable(files.join(", ")));
+ QVERIFY2(files == QStringList({ qSL("icon.png"), qSL("info.yaml"), qSL("test"), QString::fromUtf8("t\xc3\xa4st") }),
+ qPrintable(files.join(qSL(", "))));
QFile f(fileCheckPath + "/test");
QVERIFY(f.open(QFile::ReadOnly));
@@ -544,32 +497,31 @@ void tst_ApplicationInstaller::packageInstallation()
QCOMPARE(m_requestingInstallationAcknowledgeSpy->count(), 1);
QVariantMap extra = m_requestingInstallationAcknowledgeSpy->first()[2].toMap();
QVariantMap extraSigned = m_requestingInstallationAcknowledgeSpy->first()[3].toMap();
- if (extraMetaData.value("extra").toMap() != extra) {
+ if (extraMetaData.value(qSL("extra")).toMap() != extra) {
qDebug() << "Actual: " << extra;
- qDebug() << "Expected: " << extraMetaData.value("extra").toMap();
+ qDebug() << "Expected: " << extraMetaData.value(qSL("extra")).toMap();
QVERIFY(extraMetaData == extra);
}
- if (extraMetaData.value("extraSigned").toMap() != extraSigned) {
+ if (extraMetaData.value(qSL("extraSigned")).toMap() != extraSigned) {
qDebug() << "Actual: " << extraSigned;
- qDebug() << "Expected: " << extraMetaData.value("extraSigned").toMap();
+ qDebug() << "Expected: " << extraMetaData.value(qSL("extraSigned")).toMap();
QVERIFY(extraMetaData == extraSigned);
}
// check if the meta-data was saved to the installation report correctly
- QVERIFY2(m_ai->installedApplicationExtraMetaData("com.pelagicore.test") == extra,
+ QVERIFY2(m_pm->installedPackageExtraMetaData(qSL("com.pelagicore.test")) == extra,
"Extra meta-data was not correctly saved to installation report");
- QVERIFY2(m_ai->installedApplicationExtraSignedMetaData("com.pelagicore.test") == extraSigned,
+ QVERIFY2(m_pm->installedPackageExtraSignedMetaData(qSL("com.pelagicore.test")) == extraSigned,
"Extra signed meta-data was not correctly saved to installation report");
}
if (pass == lastPass && expectedSuccess) {
// remove package again
clearSignalSpies();
- taskId = m_ai->removePackage("com.pelagicore.test", false);
+ taskId = m_pm->removePackage(qSL("com.pelagicore.test"), false);
QVERIFY(!taskId.isEmpty());
// check signals
-
QVERIFY(m_finishedSpy->wait(spyTimeout));
QCOMPARE(m_finishedSpy->first()[0].toString(), taskId);
}
@@ -577,9 +529,9 @@ void tst_ApplicationInstaller::packageInstallation()
}
// check that all files are gone
- for (PathLocation pl: { Manifests, Internal0, Internal1, Documents0, Documents1 }) {
- QStringList entries = QDir(pathTo(pl)).entryList({ "com.pelagicore.test*" });
- QVERIFY2(entries.isEmpty(), qPrintable(pathTo(pl) + ": " + entries.join(", ")));
+ for (PathLocation pl: { Internal0, Documents0 }) {
+ QStringList entries = QDir(pathTo(pl)).entryList({ qSL("com.pelagicore.test*") });
+ QVERIFY2(entries.isEmpty(), qPrintable(pathTo(pl) + qSL(": ") + entries.join(qSL(", "))));
}
}
@@ -588,34 +540,31 @@ Q_DECLARE_METATYPE(std::function<bool()>)
typedef QMultiMap<QString, std::function<bool()>> FunctionMap;
Q_DECLARE_METATYPE(FunctionMap)
-void tst_ApplicationInstaller::simulateErrorConditions_data()
+void tst_PackageManager::simulateErrorConditions_data()
{
- QTest::addColumn<QString>("installationLocation");
QTest::addColumn<bool>("testUpdate");
QTest::addColumn<QString>("errorString");
QTest::addColumn<FunctionMap>("functions");
#ifdef Q_OS_LINUX
- QTest::newRow("manifests-dir-read-only") \
- << "internal-0" << false << "~could not create manifest sub-directory .*" \
- << FunctionMap { { "before-start", [this]() { return chmod(pathTo(Manifests).toLocal8Bit(), 0000) == 0; } },
- { "after-failed", [this]() { return chmod(pathTo(Manifests).toLocal8Bit(), 0777) == 0; } } };
-
QTest::newRow("applications-dir-read-only") \
- << "internal-0" << false << "~could not create installation directory .*" \
+ << false << "~could not create installation directory .*" \
<< FunctionMap { { "before-start", [this]() { return chmod(pathTo(Internal0).toLocal8Bit(), 0000) == 0; } },
{ "after-failed", [this]() { return chmod(pathTo(Internal0).toLocal8Bit(), 0777) == 0; } } };
QTest::newRow("documents-dir-read-only") \
- << "internal-0" << false << "~could not create the document directory .*" \
+ << false << "~could not create the document directory .*" \
<< FunctionMap { { "before-start", [this]() { return chmod(pathTo(Documents0).toLocal8Bit(), 0000) == 0; } },
{ "after-failed", [this]() { return chmod(pathTo(Documents0).toLocal8Bit(), 0777) == 0; } } };
#endif
}
-void tst_ApplicationInstaller::simulateErrorConditions()
+void tst_PackageManager::simulateErrorConditions()
{
- QFETCH(QString, installationLocation);
+#ifndef Q_OS_LINUX
+ QSKIP("Only tested on Linux");
+#endif
+
QFETCH(bool, testUpdate);
QFETCH(QString, errorString);
QFETCH(FunctionMap, functions);
@@ -625,34 +574,34 @@ void tst_ApplicationInstaller::simulateErrorConditions()
if (testUpdate) {
// the check will run when updating a package, so we need to install it first
- taskId = m_ai->startPackageInstallation(installationLocation, QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"));
+ taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg")));
QVERIFY(!taskId.isEmpty());
- m_ai->acknowledgePackageInstallation(taskId);
+ m_pm->acknowledgePackageInstallation(taskId);
QVERIFY(m_finishedSpy->wait(spyTimeout));
QCOMPARE(m_finishedSpy->first()[0].toString(), taskId);
clearSignalSpies();
}
- foreach (const auto &f, functions.values("before-start"))
+ foreach (const auto &f, functions.values(qSL("before-start")))
QVERIFY(f());
- taskId = m_ai->startPackageInstallation(installationLocation, QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"));
+ taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg")));
- foreach (const auto &f, functions.values("after-start"))
+ foreach (const auto &f, functions.values(qSL("after-start")))
QVERIFY(f());
- m_ai->acknowledgePackageInstallation(taskId);
+ m_pm->acknowledgePackageInstallation(taskId);
QVERIFY(m_failedSpy->wait(spyTimeout));
QCOMPARE(m_failedSpy->first()[0].toString(), taskId);
AM_CHECK_ERRORSTRING(m_failedSpy->first()[2].toString(), errorString);
clearSignalSpies();
- foreach (const auto &f, functions.values("after-failed"))
+ foreach (const auto &f, functions.values(qSL("after-failed")))
QVERIFY(f());
if (testUpdate) {
- taskId = m_ai->removePackage("com.pelagicore.test", false);
+ taskId = m_pm->removePackage(qSL("com.pelagicore.test"), false);
QVERIFY(m_finishedSpy->wait(spyTimeout));
QCOMPARE(m_finishedSpy->first()[0].toString(), taskId);
@@ -660,7 +609,7 @@ void tst_ApplicationInstaller::simulateErrorConditions()
}
-void tst_ApplicationInstaller::cancelPackageInstallation_data()
+void tst_PackageManager::cancelPackageInstallation_data()
{
QTest::addColumn<bool>("expectedResult");
@@ -672,28 +621,28 @@ void tst_ApplicationInstaller::cancelPackageInstallation_data()
QTest::newRow("after-finished-signal") << false;
}
-void tst_ApplicationInstaller::cancelPackageInstallation()
+void tst_PackageManager::cancelPackageInstallation()
{
QFETCH(bool, expectedResult);
- QString taskId = m_ai->startPackageInstallation("internal-0", QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"));
+ QString taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg")));
QVERIFY(!taskId.isEmpty());
if (isDataTag("before-started-signal")) {
- QCOMPARE(m_ai->cancelTask(taskId), expectedResult);
+ QCOMPARE(m_pm->cancelTask(taskId), expectedResult);
} else if (isDataTag("after-started-signal")) {
QVERIFY(m_startedSpy->wait(spyTimeout));
QCOMPARE(m_startedSpy->first()[0].toString(), taskId);
- QCOMPARE(m_ai->cancelTask(taskId), expectedResult);
+ QCOMPARE(m_pm->cancelTask(taskId), expectedResult);
} else if (isDataTag("after-blocking-until-installation-acknowledge-signal")) {
QVERIFY(m_blockingUntilInstallationAcknowledgeSpy->wait(spyTimeout));
QCOMPARE(m_blockingUntilInstallationAcknowledgeSpy->first()[0].toString(), taskId);
- QCOMPARE(m_ai->cancelTask(taskId), expectedResult);
+ QCOMPARE(m_pm->cancelTask(taskId), expectedResult);
} else if (isDataTag("after-finished-signal")) {
- m_ai->acknowledgePackageInstallation(taskId);
+ m_pm->acknowledgePackageInstallation(taskId);
QVERIFY(m_finishedSpy->wait(spyTimeout));
QCOMPARE(m_finishedSpy->first()[0].toString(), taskId);
- QCOMPARE(m_ai->cancelTask(taskId), expectedResult);
+ QCOMPARE(m_pm->cancelTask(taskId), expectedResult);
}
if (expectedResult) {
@@ -705,7 +654,7 @@ void tst_ApplicationInstaller::cancelPackageInstallation()
} else {
clearSignalSpies();
- taskId = m_ai->removePackage("com.pelagicore.test", false);
+ taskId = m_pm->removePackage(qSL("com.pelagicore.test"), false);
QVERIFY(!taskId.isEmpty());
QVERIFY(m_finishedSpy->wait(spyTimeout));
QCOMPARE(m_finishedSpy->first()[0].toString(), taskId);
@@ -713,46 +662,28 @@ void tst_ApplicationInstaller::cancelPackageInstallation()
clearSignalSpies();
}
-void tst_ApplicationInstaller::parallelPackageInstallation()
+void tst_PackageManager::parallelPackageInstallation()
{
- QString task1Id = m_ai->startPackageInstallation("internal-0", QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"));
+ QString task1Id = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg")));
QVERIFY(!task1Id.isEmpty());
QVERIFY(m_blockingUntilInstallationAcknowledgeSpy->wait(spyTimeout));
QCOMPARE(m_blockingUntilInstallationAcknowledgeSpy->first()[0].toString(), task1Id);
- QString task2Id = m_ai->startPackageInstallation("internal-0", QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/bigtest-dev-signed.appkg"));
+ QString task2Id = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/bigtest-dev-signed.appkg")));
QVERIFY(!task2Id.isEmpty());
- m_ai->acknowledgePackageInstallation(task2Id);
+ m_pm->acknowledgePackageInstallation(task2Id);
QVERIFY(m_finishedSpy->wait(spyTimeout));
QCOMPARE(m_finishedSpy->first()[0].toString(), task2Id);
clearSignalSpies();
- m_ai->acknowledgePackageInstallation(task1Id);
+ m_pm->acknowledgePackageInstallation(task1Id);
QVERIFY(m_finishedSpy->wait(spyTimeout));
QCOMPARE(m_finishedSpy->first()[0].toString(), task1Id);
clearSignalSpies();
}
-
-static tst_ApplicationInstaller *tstApplicationInstaller = nullptr;
-
-int main(int argc, char **argv)
-{
- Package::ensureCorrectLocale();
-
- try {
- Sudo::forkServer(Sudo::DropPrivilegesPermanently);
- startedSudoServer = true;
- } catch (...) { }
-
- QCoreApplication a(argc, argv);
- tstApplicationInstaller = new tst_ApplicationInstaller(&a);
-
- return QTest::qExec(tstApplicationInstaller, argc, argv);
-}
-
-void tst_ApplicationInstaller::validateDnsName_data()
+void tst_PackageManager::validateDnsName_data()
{
QTest::addColumn<QString>("dnsName");
QTest::addColumn<int>("minParts");
@@ -783,19 +714,19 @@ void tst_ApplicationInstaller::validateDnsName_data()
QTest::newRow("part-too-long") << "com.x012345678901234567890123456789012345678901234567890123456789012.test" << 3 << false;
}
-void tst_ApplicationInstaller::validateDnsName()
+void tst_PackageManager::validateDnsName()
{
QFETCH(QString, dnsName);
QFETCH(int, minParts);
QFETCH(bool, valid);
QString errorString;
- bool result = m_ai->validateDnsName(dnsName, minParts);
+ bool result = m_pm->validateDnsName(dnsName, minParts);
QVERIFY2(valid == result, qPrintable(errorString));
}
-void tst_ApplicationInstaller::compareVersions_data()
+void tst_PackageManager::compareVersions_data()
{
QTest::addColumn<QString>("version1");
QTest::addColumn<QString>("version2");
@@ -826,19 +757,36 @@ void tst_ApplicationInstaller::compareVersions_data()
QTest::newRow("21") << "12.403.51-alpha2+git" << "13.403.51-alpha2+git" << -1;
}
-void tst_ApplicationInstaller::compareVersions()
+void tst_PackageManager::compareVersions()
{
QFETCH(QString, version1);
QFETCH(QString, version2);
QFETCH(int, result);
- int cmp = m_ai->compareVersions(version1, version2);
+ int cmp = m_pm->compareVersions(version1, version2);
QCOMPARE(cmp, result);
if (result) {
- cmp = m_ai->compareVersions(version2, version1);
+ cmp = m_pm->compareVersions(version2, version1);
QCOMPARE(cmp, -result);
}
}
+static tst_PackageManager *tstPackageManager = nullptr;
+
+int main(int argc, char **argv)
+{
+ PackageUtilities::ensureCorrectLocale();
+
+ try {
+ Sudo::forkServer(Sudo::DropPrivilegesPermanently);
+ startedSudoServer = true;
+ } catch (...) { }
+
+ QCoreApplication a(argc, argv);
+ tstPackageManager = new tst_PackageManager(&a);
+
+ return QTest::qExec(tstPackageManager, argc, argv);
+}
+
#include "tst_applicationinstaller.moc"
diff --git a/tests/cryptography/tst_cryptography.cpp b/tests/cryptography/tst_cryptography.cpp
index 21f679ca..874b8eb2 100644
--- a/tests/cryptography/tst_cryptography.cpp
+++ b/tests/cryptography/tst_cryptography.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/tests/data/certificates/create-test-certificates.sh b/tests/data/certificates/create-test-certificates.sh
index 0615418e..960b736f 100755
--- a/tests/data/certificates/create-test-certificates.sh
+++ b/tests/data/certificates/create-test-certificates.sh
@@ -5,7 +5,7 @@
## Copyright (C) 2018 Pelagicore AG
## Contact: https://www.qt.io/licensing/
##
-## This file is part of the Luxoft Application Manager.
+## This file is part of the Qt Application Manager.
##
## $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
## Commercial License Usage
diff --git a/tests/data/create-test-packages.sh b/tests/data/create-test-packages.sh
index 8355e462..3bc17175 100755
--- a/tests/data/create-test-packages.sh
+++ b/tests/data/create-test-packages.sh
@@ -5,7 +5,7 @@
## Copyright (C) 2018 Pelagicore AG
## Contact: https://www.qt.io/licensing/
##
-## This file is part of the Luxoft Application Manager.
+## This file is part of the Qt Application Manager.
##
## $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
## Commercial License Usage
@@ -78,8 +78,10 @@ mkdir -p "$src"
packager()
{
+ set +e
packagerOutput=`"$PACKAGER" "$@" 2>&1`
packagerResult=$?
+ set -e
if [ $packagerResult -ne 0 ]; then
echo -e "`basename $PACKAGER`$R failed with exit code $packagerResult$W. The executed command was:"
echo
@@ -153,6 +155,7 @@ packager create-package "$dst/hello-world.red.appkg" hello-world.red
### v2 packages for testing updates
echo "test update" >"$src/test"
+sed -i 's/version: 1.0/version: 2.0/' "$src/info.yaml"
info "Create update package"
packager create-package "$dst/test-update.appkg" "$src"
@@ -161,6 +164,7 @@ info "Dev-sign update package"
packager dev-sign-package "$dst/test-update.appkg" "$dst/test-update-dev-signed.appkg" certificates/dev2.p12 password
echo "test" >"$src/test"
+sed -i 's/version: 2.0/version: 1.0/' "$src/info.yaml"
### big packages
@@ -185,7 +189,7 @@ echo "invalid" >"$dst/test-invalid-format.appkg"
info "Create a package with an invalid formatVersion header field"
mv "$src"/--PACKAGE-HEADER--{,.orig}
-echo '{formatType: "am-package-header", formatVersion: 2}' >$src/--PACKAGE-HEADER--
+sed <"$src/--PACKAGE-HEADER--.orig" >"$src/--PACKAGE-HEADER--" 's/formatVersion: 2/formatVersion: X/'
tar -C "$src" -cf "$dst/test-invalid-header-formatversion.appkg" -- --PACKAGE-HEADER-- info.yaml icon.png test --PACKAGE-FOOTER--
mv "$src"/--PACKAGE-HEADER--{.orig,}
@@ -197,13 +201,13 @@ mv "$src"/--PACKAGE-HEADER--{.orig,}
info "Create a package with an invalid id header field"
mv "$src"/--PACKAGE-HEADER--{,.orig}
-sed <"$src/--PACKAGE-HEADER--.orig" >"$src/--PACKAGE-HEADER--" "s/applicationId: '[a-z0-9.-]*'/applicationId: ':invalid'/"
+sed <"$src/--PACKAGE-HEADER--.orig" >"$src/--PACKAGE-HEADER--" "s/packageId: '[a-z0-9.-]*'/packageId: ':invalid'/"
tar -C "$src" -cf "$dst/test-invalid-header-id.appkg" -- --PACKAGE-HEADER-- info.yaml icon.png test --PACKAGE-FOOTER--
mv "$src"/--PACKAGE-HEADER--{.orig,}
info "Create a package with a non-matching id header field"
mv "$src"/--PACKAGE-HEADER--{,.orig}
-sed <"$src/--PACKAGE-HEADER--.orig" >"$src/--PACKAGE-HEADER--" "s/applicationId: '[a-z0-9.-]*'/applicationId: 'non-matching'/"
+sed <"$src/--PACKAGE-HEADER--.orig" >"$src/--PACKAGE-HEADER--" "s/packageId: '[a-z0-9.-]*'/packageId: 'non-matching'/"
tar -C "$src" -cf "$dst/test-non-matching-header-id.appkg" -- --PACKAGE-HEADER-- info.yaml icon.png test --PACKAGE-FOOTER--
mv "$src"/--PACKAGE-HEADER--{.orig,}
diff --git a/tests/data/hello-world.red/info.yaml b/tests/data/hello-world.red/info.yaml
index af6a9f70..77980428 100644
--- a/tests/data/hello-world.red/info.yaml
+++ b/tests/data/hello-world.red/info.yaml
@@ -7,3 +7,4 @@ code: 'main.qml'
runtime: 'qml'
name:
en: 'Hello Updated Red'
+version: red
diff --git a/tests/data/manifests/com.pelagicore.test/info.yaml b/tests/data/manifests/com.pelagicore.test/info.yaml
index f7fc13a3..0c4b3fd0 100644
--- a/tests/data/manifests/com.pelagicore.test/info.yaml
+++ b/tests/data/manifests/com.pelagicore.test/info.yaml
@@ -11,6 +11,8 @@ name:
en: 'english'
de: 'deutsch'
+version: v1
+
mimeTypes:
- "x-scheme-handler/mailto"
- "text/plain"
diff --git a/tests/data/utilities.sh b/tests/data/utilities.sh
index add548f2..9d6b8ad9 100755
--- a/tests/data/utilities.sh
+++ b/tests/data/utilities.sh
@@ -4,7 +4,7 @@
## Copyright (C) 2018 Pelagicore AG
## Contact: https://www.qt.io/licensing/
##
-## This file is part of the Luxoft Application Manager.
+## This file is part of the Qt Application Manager.
##
## $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
## Commercial License Usage
diff --git a/tests/debugwrapper/tst_debugwrapper.cpp b/tests/debugwrapper/tst_debugwrapper.cpp
index bb1525ca..3d85c2be 100644
--- a/tests/debugwrapper/tst_debugwrapper.cpp
+++ b/tests/debugwrapper/tst_debugwrapper.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/tests/error-checking.h b/tests/error-checking.h
index 7b25a776..09d3f61f 100644
--- a/tests/error-checking.h
+++ b/tests/error-checking.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -34,7 +34,7 @@
// sadly this has to be a define for QVERIFY2() to work
#define AM_CHECK_ERRORSTRING(_actual_errstr, _expected_errstr) do { \
if (_expected_errstr.startsWith(QLatin1String("~"))) { \
- QRegularExpression re(QStringLiteral("\\A") + _expected_errstr.mid(1) + QStringLiteral("\\z")); \
+ QRegularExpression re(_expected_errstr.mid(1)); \
QVERIFY2(re.match(_actual_errstr).hasMatch(), \
qPrintable("\n Got : " + _actual_errstr.toLocal8Bit() + \
"\n Expected: " + _expected_errstr.toLocal8Bit())); \
diff --git a/tests/installationreport/tst_installationreport.cpp b/tests/installationreport/tst_installationreport.cpp
index 81a25443..6e7e4cd8 100644
--- a/tests/installationreport/tst_installationreport.cpp
+++ b/tests/installationreport/tst_installationreport.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -31,6 +32,7 @@
#include <QtTest>
#include "global.h"
+#include "exception.h"
#include "installationreport.h"
QT_USE_NAMESPACE_AM
@@ -62,16 +64,14 @@ void tst_InstallationReport::test()
ir.setDigest("##digest##");
QVERIFY(ir.isValid());
ir.addFiles(files.mid(1));
- ir.setInstallationLocationId(qSL("test-42"));
ir.setDeveloperSignature("%%dev-sig%%");
ir.setStoreSignature("$$store-sig$$");
QVERIFY(ir.isValid());
- QCOMPARE(ir.applicationId(), qSL("com.pelagicore.test"));
+ QCOMPARE(ir.packageId(), qSL("com.pelagicore.test"));
QCOMPARE(ir.files(), files);
QCOMPARE(ir.diskSpaceUsed(), 42ULL);
QCOMPARE(ir.digest().constData(), "##digest##");
- QCOMPARE(ir.installationLocationId(), qSL("test-42"));
QCOMPARE(ir.developerSignature().constData(), "%%dev-sig%%");
QCOMPARE(ir.storeSignature().constData(), "$$store-sig$$");
@@ -81,15 +81,18 @@ void tst_InstallationReport::test()
buffer.seek(0);
InstallationReport ir2;
- QVERIFY(ir2.deserialize(&buffer));
+ try {
+ ir2.deserialize(&buffer);
+ } catch (const Exception &e) {
+ QVERIFY2(false, e.what());
+ }
buffer.seek(0);
QVERIFY(ir2.isValid());
- QCOMPARE(ir2.applicationId(), qSL("com.pelagicore.test"));
+ QCOMPARE(ir2.packageId(), qSL("com.pelagicore.test"));
QCOMPARE(ir2.files(), files);
QCOMPARE(ir2.diskSpaceUsed(), 42ULL);
QCOMPARE(ir2.digest().constData(), "##digest##");
- QCOMPARE(ir2.installationLocationId(), qSL("test-42"));
QCOMPARE(ir2.developerSignature().constData(), "%%dev-sig%%");
QCOMPARE(ir2.storeSignature().constData(), "$$store-sig$$");
@@ -103,7 +106,11 @@ void tst_InstallationReport::test()
yaml.replace(pos, hmac.size(), hmac);
QCOMPARE(yaml.mid(pos + hmac.size(), 2).constData(), "'\n");
- QVERIFY(!ir2.deserialize(&buffer));
+ try {
+ ir2.deserialize(&buffer);
+ QVERIFY(false);
+ } catch (...) {
+ }
}
QTEST_APPLESS_MAIN(tst_InstallationReport)
diff --git a/tests/main/am-config.yaml b/tests/main/am-config.yaml
index a7a60179..ff538f1b 100644
--- a/tests/main/am-config.yaml
+++ b/tests/main/am-config.yaml
@@ -3,12 +3,8 @@ formatType: am-configuration
---
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/builtin-apps"
- installedAppsManifestDir: "/tmp/am-test-main/manifests"
- database: "/tmp/am-test-main/apps.db"
+ installationDir: "/tmp/am-test-main/apps"
+ documentDir: "/tmp/am-test-main/docs"
-installationLocations:
-- id: "internal-0"
- installationPath: "/tmp/am-test-main/apps"
- documentPath: "/tmp/am-test-main/docs"
- mountPoint: "/tmp"
- isDefault: true
+ui:
+ mainQml: "${CONFIG_PWD}/dummy.qml"
diff --git a/tests/main/builtin-apps/hello-world.red/info.yaml b/tests/main/builtin-apps/hello-world.red/info.yaml
index fe0be9af..fa52180e 100644
--- a/tests/main/builtin-apps/hello-world.red/info.yaml
+++ b/tests/main/builtin-apps/hello-world.red/info.yaml
@@ -1,9 +1,24 @@
formatVersion: 1
-formatType: am-application
+formatType: am-package
---
id: 'hello-world.red'
icon: 'icon.png'
-code: 'main.qml'
-runtime: 'qml'
name:
en: 'Hello Red'
+
+applications:
+- id: red1
+ runtime: 'qml'
+ code: 'main.qml'
+
+- id: red2
+ runtime: 'qml'
+ code: 'main2.qml'
+
+intents:
+- id: red.intent1
+ handlingApplicationId: red1
+ categories: [ launcher, one ]
+- id: red.intent2
+ handlingApplicationId: red2
+ categories: [ launcher, two ]
diff --git a/tests/main/dir-with-update-already-installed/manifests/hello-world.red/installation-report.yaml b/tests/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml
index 872f97d6..ec57b3d7 100644
--- a/tests/main/dir-with-update-already-installed/manifests/hello-world.red/installation-report.yaml
+++ b/tests/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml
@@ -1,15 +1,14 @@
%YAML 1.1
---
formatType: 'am-installation-report'
-formatVersion: 1
+formatVersion: 3
---
-applicationId: 'hello-world.red'
+packageId: 'hello-world.red'
digest: '45ca0f9dfbddca129687900ae3260fe4a35ca09efd189581e196c0a75da47a0f'
diskSpaceUsed: 575488
files:
- 'info.yaml'
- 'icon.png'
- 'main.qml'
-installationLocationId: 'internal-0'
---
-hmac: '98cc78740bf87707de6163879b611f96f8fd2faf592218afa4f5361836d81caf'
+hmac: '48fce75b29a2b621f1a1462b434e6de0cac78837fe733bc12ab8e727363c5226'
diff --git a/tests/main/dummy.qml b/tests/main/dummy.qml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/main/dummy.qml
diff --git a/tests/main/main.pro b/tests/main/main.pro
index af74b450..e60ec75f 100644
--- a/tests/main/main.pro
+++ b/tests/main/main.pro
@@ -10,5 +10,11 @@ QT *= appman_manager-private \
appman_application-private \
appman_common-private \
appman_main-private \
+ appman_intent_server-private \
SOURCES += tst_main.cpp
+
+RESOURCES = main.qrc
+
+OTHER_FILES += am-config.yaml
+
diff --git a/tests/main/main.qrc b/tests/main/main.qrc
new file mode 100644
index 00000000..8cae2bbb
--- /dev/null
+++ b/tests/main/main.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/foo">
+ <file>dummy.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/main/tst_main.cpp b/tests/main/tst_main.cpp
index 7ec32116..d87f1b88 100644
--- a/tests/main/tst_main.cpp
+++ b/tests/main/tst_main.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -33,10 +34,12 @@
#include <QString>
#include <QStringList>
-#include "applicationinstaller.h"
+#include "packagemanager.h"
#include "applicationmanager.h"
#include "logging.h"
#include "main.h"
+#include "intentserver.h"
+#include "intent.h"
#include <QtAppManMain/defaultconfiguration.h>
@@ -57,7 +60,8 @@ private slots:
void installAndRemoveUpdateForBuiltIn();
void updateForBuiltInAlreadyInstalled();
void loadDatabaseWithUpdatedBuiltInApp();
- void nonExistentMainQmlFile();
+ void mainQmlFile_data();
+ void mainQmlFile();
private:
void cleanUpInstallationDir();
@@ -76,13 +80,11 @@ private:
tst_Main::tst_Main()
{
argc = 3;
- argv = new char*[3];
- argv[0] = new char[255];
- sprintf(argv[0], "tst_update-builtin-app");
- argv[1] = new char[255];
- sprintf(argv[1], "--dbus");
- argv[2] = new char[255];
- sprintf(argv[2], "none");
+ argv = new char*[argc + 1];
+ argv[0] = qstrdup("tst_update-builtin-app");
+ argv[1] = qstrdup("--dbus");
+ argv[2] = qstrdup("none");
+ argv[3] = nullptr;
}
tst_Main::~tst_Main()
@@ -112,7 +114,7 @@ void tst_Main::copyRecursively(const QString &sourcePath, const QString &destPat
copyRecursively(sourceDir.filePath(subdirName), destDir.filePath(subdirName));
}
- QStringList fileNames = sourceDir.entryList(QDir::Files);
+ QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Hidden);
for (auto fileName : fileNames)
QFile::copy(sourceDir.filePath(fileName), destDir.filePath(fileName));
}
@@ -144,12 +146,12 @@ void tst_Main::initMain()
config = new DefaultConfiguration(pathList, QString());
config->parse(&deploymentWarnings);
+ if (m_verbose)
+ config->setForceVerbose(true);
main->setup(config, deploymentWarnings);
- if (m_verbose)
- Logging::setFilterRules(Logging::filterRules() += qSL("am.installer.debug=true"));
- ApplicationInstaller::instance()->setAllowInstallationOfUnsignedPackages(true);
+ PackageManager::instance()->setAllowInstallationOfUnsignedPackages(true);
}
void tst_Main::destroyMain()
@@ -172,40 +174,41 @@ void tst_Main::cleanup()
void tst_Main::installPackage(const QString &pkgPath)
{
- auto appInstaller = ApplicationInstaller::instance();
+ auto packageManager = PackageManager::instance();
bool installationFinished = false;
- connect(appInstaller, &ApplicationInstaller::taskRequestingInstallationAcknowledge,
- this, [this, appInstaller](const QString &taskId, const QVariantMap &,
- const QVariantMap &, const QVariantMap &) {
- appInstaller->acknowledgePackageInstallation(taskId);
+ connect(packageManager, &PackageManager::taskRequestingInstallationAcknowledge,
+ this, [packageManager](const QString &taskId, const QVariantMap &,
+ const QVariantMap &, const QVariantMap &) {
+ packageManager->acknowledgePackageInstallation(taskId);
});
- connect(appInstaller, &ApplicationInstaller::taskFinished,
- this, [this, &installationFinished](const QString &) {
+ connect(packageManager, &PackageManager::taskFinished,
+ this, [&installationFinished](const QString &) {
installationFinished = true;
});
- appInstaller->startPackageInstallation(qSL("internal-0"), QUrl::fromLocalFile(pkgPath));
+ packageManager->startPackageInstallation(QUrl::fromLocalFile(pkgPath));
- QTRY_COMPARE(installationFinished, true);
+ QTRY_VERIFY(installationFinished);
}
void tst_Main::removePackage(const QString &id)
{
- auto appInstaller = ApplicationInstaller::instance();
+ auto packageManager = PackageManager::instance();
bool removalFinished = false;
- connect(appInstaller, &ApplicationInstaller::taskFinished,
+ connect(packageManager, &PackageManager::taskFinished,
this, [this, &removalFinished](const QString &) {
- removalFinished = true;
+ Q_UNUSED(this); // gcc 9.2 bug: without capturing 'this', broken code will be generated
+ removalFinished = true;
});
- appInstaller->removePackage(id, false /* keepDocuments */);
+ packageManager->removePackage(id, false /* keepDocuments */);
- QTRY_COMPARE(removalFinished, true);
+ QTRY_VERIFY(removalFinished);
}
/*
@@ -220,26 +223,62 @@ void tst_Main::installAndRemoveUpdateForBuiltIn()
initMain();
auto appMan = ApplicationManager::instance();
- QCOMPARE(appMan->count(), 1);
-
- auto app = appMan->application(0);
- QCOMPARE(app->name(qSL("en")), qSL("Hello Red"));
+ QCOMPARE(appMan->count(), 2);
+ auto intents = IntentServer::instance();
+ QCOMPARE(intents->count(), 2);
+
+ auto app1 = appMan->application(0);
+ QCOMPARE(app1->name(qSL("en")), qSL("Hello Red"));
+ QCOMPARE(app1->id(), qSL("red1"));
+ auto app2 = appMan->application(1);
+ QCOMPARE(app2->name(qSL("en")), qSL("Hello Red"));
+ QCOMPARE(app2->id(), qSL("red2"));
+
+ auto intent1 = intents->applicationIntent(qSL("red.intent1"), qSL("red1"));
+ QVERIFY(intent1);
+ QCOMPARE(intent1->intentId(), qSL("red.intent1"));
+ QCOMPARE(intent1->applicationId(), qSL("red1"));
+ QCOMPARE(intent1->packageId(), qSL("hello-world.red"));
+ QVERIFY(intent1->categories().contains(qSL("one")));
+ QVERIFY(intent1->categories().contains(qSL("launcher")));
+
+ auto intent2 = intents->applicationIntent(qSL("red.intent2"), qSL("red2"));
+ QVERIFY(intent2);
+ QCOMPARE(intent2->intentId(), qSL("red.intent2"));
+ QCOMPARE(intent2->applicationId(), qSL("red2"));
+ QCOMPARE(intent2->packageId(), qSL("hello-world.red"));
+ QVERIFY(intent2->categories().contains(qSL("two")));
+ QVERIFY(intent2->categories().contains(qSL("launcher")));
installPackage(qL1S(AM_TESTDATA_DIR "packages/hello-world.red.appkg"));
QCOMPARE(appMan->count(), 1);
- // it must still be the same Application instance as before the installation
- QCOMPARE(appMan->application(0), app);
+ QCOMPARE(intents->count(), 0);
+
+ // it must still be a different Application instance as before the installation, but quite
+ // often we get the same pointer back because it's a delete/new back-to-back
+ app1 = appMan->application(0);
+
// but with different contents
- QCOMPARE(app->name(qSL("en")), qSL("Hello Updated Red"));
+ QCOMPARE(app1->name(qSL("en")), qSL("Hello Updated Red"));
+ intent1 = intents->applicationIntent(qSL("red.intent1"), qSL("red1"));
+ QVERIFY(!intent1);
removePackage(qSL("hello-world.red"));
// After removal of the updated version all data in Application should be as before the
// installation took place.
- QCOMPARE(appMan->count(), 1);
- QCOMPARE(appMan->application(0), app);
- QCOMPARE(app->name(qSL("en")), qSL("Hello Red"));
+ QCOMPARE(appMan->count(), 2);
+ QCOMPARE(intents->count(), 2);
+
+ app1 = appMan->application(0);
+ QCOMPARE(app1->name(qSL("en")), qSL("Hello Red"));
+ intent1 = intents->applicationIntent(qSL("red.intent1"), qSL("red1"));
+ QVERIFY(intent1);
+ QCOMPARE(intent1->intentId(), qSL("red.intent1"));
+ intent2 = intents->applicationIntent(qSL("red.intent2"), qSL("red2"));
+ QVERIFY(intent2);
+ QCOMPARE(intent2->intentId(), qSL("red.intent2"));
}
/*
@@ -272,14 +311,10 @@ void tst_Main::updateForBuiltInAlreadyInstalled()
*/
void tst_Main::loadDatabaseWithUpdatedBuiltInApp()
{
- QCOMPARE(QFile::exists("/tmp/am-test-main/apps.db"), false);
-
initMain();
installPackage(qL1S(AM_TESTDATA_DIR "packages/hello-world.red.appkg"));
destroyMain();
- QCOMPARE(QFile::exists("/tmp/am-test-main/apps.db"), true);
-
initMain();
auto appMan = ApplicationManager::instance();
@@ -289,35 +324,52 @@ void tst_Main::loadDatabaseWithUpdatedBuiltInApp()
QCOMPARE(app->name(qSL("en")), qSL("Hello Updated Red"));
}
-/*
- When the "main QML file" parameter contains a relative filepath like "foo/bar.qml",
- Main should treat it as a local file (instead of a remote url) and complain that it
- doesn't exist.
- */
-void tst_Main::nonExistentMainQmlFile()
+void tst_Main::mainQmlFile_data()
{
+ QTest::addColumn<QString>("mainQml");
+ QTest::addColumn<QString>("expectedErrorMsg");
+
+ QTest::newRow("none") << "" << "No main QML file specified";
+
+ QTest::newRow("invalid") << "foo/bar.qml" << "Invalid main QML file specified: foo/bar.qml";
+ QTest::newRow("invalid-dir") << "." << "Invalid main QML file specified: .";
+ QTest::newRow("invalid-qrc1") << ":/bar.qml" << "Invalid main QML file specified: :/bar.qml";
+ // "://bar.qml" yields an absolute file path of ":" and QFile::exists() would always return true
+ QTest::newRow("invalid-qrc2") << "://bar.qml" << "Invalid main QML file specified: ://bar.qml";
+ QTest::newRow("invalid-qrc-dir") << ":/foo" << "Invalid main QML file specified: :/foo";
+
+ QTest::newRow("valid-native") << QFINDTESTDATA("dummy.qml") << "";
+ QTest::newRow("valid-qrc-file") << ":/foo/dummy.qml" << "";
+ QTest::newRow("valid-qrc-url") << "qrc:///foo/dummy.qml" << "";
+
+ // Passes unchecked:
+ QTest::newRow("https") << "https://www.qt.io/foo/bar.qml" << "";
+ QTest::newRow("assets") << "assets:///foo/bar.qml" << "";
+}
+
+void tst_Main::mainQmlFile()
+{
+ QFETCH(QString, mainQml);
+ QFETCH(QString, expectedErrorMsg);
+
QStringList arguments;
arguments << "tst_update-builtin-app";
arguments << "--dbus";
arguments << "none";
- arguments << "foo/bar.qml";
-
- QString errorMsg;
+ arguments << mainQml;
main = new Main(argc, argv);
- config = new DefaultConfiguration;
+ config = new DefaultConfiguration(QStringList(QFINDTESTDATA("am-config.yaml")), QString());
config->parseWithArguments(arguments);
try {
main->setup(config);
+ QVERIFY2(expectedErrorMsg.isEmpty(), "Exception was expected, but none was thrown");
} catch (const std::exception &e) {
- errorMsg.append(e.what());
+ QCOMPARE(e.what(), expectedErrorMsg);
}
- QVERIFY(errorMsg.startsWith("no/invalid main QML file specified:"));
- QVERIFY(errorMsg.contains("bar.qml"));
-
delete config;
config = nullptr;
delete main;
diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro
new file mode 100644
index 00000000..49d5c3b4
--- /dev/null
+++ b/tests/manual/manual.pro
@@ -0,0 +1,6 @@
+requires(false) # visible in QtCreator, but not built by default
+
+TEMPLATE = subdirs
+
+SUBDIRS = \
+ monitormodel \
diff --git a/tests/manual/monitormodel/PropertyField.qml b/tests/manual/monitormodel/PropertyField.qml
index d40a5358..042b7545 100644
--- a/tests/manual/monitormodel/PropertyField.qml
+++ b/tests/manual/monitormodel/PropertyField.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/manual/monitormodel/SystemMonitorChart.qml b/tests/manual/monitormodel/SystemMonitorChart.qml
index 264c9dcf..8a45d584 100644
--- a/tests/manual/monitormodel/SystemMonitorChart.qml
+++ b/tests/manual/monitormodel/SystemMonitorChart.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/manual/monitormodel/main.qml b/tests/manual/monitormodel/main.qml
index 3ac2c727..688810d9 100644
--- a/tests/manual/monitormodel/main.qml
+++ b/tests/manual/monitormodel/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -45,7 +45,7 @@ import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11
import QtQuick.Window 2.11
-import QtApplicationManager.SystemUI 2.0
+import QtApplicationManager 2.0
Window {
width: 1200
diff --git a/tests/manual/monitormodel/monitormodel.pro b/tests/manual/monitormodel/monitormodel.pro
new file mode 100644
index 00000000..7c2e33bc
--- /dev/null
+++ b/tests/manual/monitormodel/monitormodel.pro
@@ -0,0 +1,5 @@
+TEMPLATE = aux
+
+OTHER_FILES = \
+ *.qml \
+ README \
diff --git a/tests/packagecreator/tst_packagecreator.cpp b/tests/packagecreator/tst_packagecreator.cpp
index 1b030168..0f1af7e1 100644
--- a/tests/packagecreator/tst_packagecreator.cpp
+++ b/tests/packagecreator/tst_packagecreator.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -31,7 +31,7 @@
#include "global.h"
#include "installationreport.h"
-#include "package.h"
+#include "packageutilities.h"
#include "packagecreator.h"
#include "utilities.h"
@@ -80,7 +80,7 @@ void tst_PackageCreator::initTestCase()
m_isCygwin = tar.readAllStandardOutput().contains("Cygwin");
- QVERIFY(Package::checkCorrectLocale());
+ QVERIFY(PackageUtilities::checkCorrectLocale());
}
void tst_PackageCreator::createAndVerify_data()
@@ -173,7 +173,7 @@ QString tst_PackageCreator::escapeFilename(const QString &name)
int main(int argc, char *argv[])
{
- Package::ensureCorrectLocale();
+ PackageUtilities::ensureCorrectLocale();
QCoreApplication app(argc, argv);
app.setAttribute(Qt::AA_Use96Dpi, true);
tst_PackageCreator tc;
diff --git a/tests/packageextractor/tst_packageextractor.cpp b/tests/packageextractor/tst_packageextractor.cpp
index 950639e0..32979bb9 100644
--- a/tests/packageextractor/tst_packageextractor.cpp
+++ b/tests/packageextractor/tst_packageextractor.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -41,7 +41,7 @@
#include "global.h"
#include "packageextractor.h"
#include "installationreport.h"
-#include "package.h"
+#include "packageutilities.h"
#include "../error-checking.h"
@@ -80,7 +80,7 @@ void tst_PackageExtractor::initTestCase()
if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists())
QSKIP("No test packages available in the data/ directory");
- QVERIFY(Package::checkCorrectLocale());
+ QVERIFY(PackageUtilities::checkCorrectLocale());
}
void tst_PackageExtractor::init()
@@ -300,7 +300,7 @@ void tst_PackageExtractor::extractFromFifo()
int main(int argc, char *argv[])
{
- Package::ensureCorrectLocale();
+ PackageUtilities::ensureCorrectLocale();
QCoreApplication app(argc, argv);
app.setAttribute(Qt::AA_Use96Dpi, true);
tst_PackageExtractor tc;
diff --git a/tests/packager-tool/packager-tool.pro b/tests/packager-tool/packager-tool.pro
index b4c11d94..08876ac6 100644
--- a/tests/packager-tool/packager-tool.pro
+++ b/tests/packager-tool/packager-tool.pro
@@ -8,9 +8,8 @@ QT *= \
appman_application-private \
appman_package-private \
appman_manager-private \
- appman_installer-private \
-INCLUDEPATH += ../../src/tools/packager
-SOURCES += ../../src/tools/packager/packagingjob.cpp
+INCLUDEPATH += $$PWD/../../src/tools/packager
+SOURCES += $$PWD/../../src/tools/packager/packagingjob.cpp
SOURCES += tst_packager-tool.cpp
diff --git a/tests/packager-tool/tst_packager-tool.cpp b/tests/packager-tool/tst_packager-tool.cpp
index e890f066..c97a8317 100644
--- a/tests/packager-tool/tst_packager-tool.cpp
+++ b/tests/packager-tool/tst_packager-tool.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -31,13 +32,13 @@
#include <QCoreApplication>
#include "global.h"
-#include "installationlocation.h"
#include "applicationmanager.h"
#include "application.h"
#include "qtyaml.h"
#include "exception.h"
+#include "packagedatabase.h"
+#include "packagemanager.h"
#include "packagingjob.h"
-#include "applicationinstaller.h"
#include "qmlinprocessruntime.h"
#include "runtimefactory.h"
#include "utilities.h"
@@ -74,7 +75,7 @@ private:
void installPackage(const QString &filePath);
- ApplicationInstaller *m_ai = nullptr;
+ PackageManager *m_pm = nullptr;
QTemporaryDir m_workDir;
QString m_devPassword;
@@ -93,23 +94,18 @@ void tst_PackagerTool::initTestCase()
spyTimeout *= timeoutFactor();
QVERIFY(m_workDir.isValid());
-
- QVERIFY(QDir::root().mkpath(pathTo("manifests")));
QVERIFY(QDir::root().mkpath(pathTo("internal-0")));
QVERIFY(QDir::root().mkpath(pathTo("documents-0")));
- m_hardwareId = "foobar";
-
- QVariantMap internalLocation {
- { "id", "internal-0" },
- { "installationPath", pathTo("internal-0") },
- { "documentPath", pathTo("documents-0") },
- };
- QVector<InstallationLocation> locations = InstallationLocation::parseInstallationLocations({ internalLocation }, m_hardwareId);
+ m_hardwareId = qSL("foobar");
- QString errorString;
- m_ai = ApplicationInstaller::createInstance(locations, pathTo("manifests"), m_hardwareId, &errorString);
- QVERIFY2(m_ai, qPrintable(errorString));
+ PackageDatabase *pdb = new PackageDatabase({}, pathTo("internal-0"));
+ try {
+ m_pm = PackageManager::createInstance(pdb, pathTo("documents-0"));
+ m_pm->setHardwareId(m_hardwareId);
+ } catch (const Exception &e) {
+ QVERIFY2(false, e.what());
+ }
QVERIFY(ApplicationManager::createInstance(true));
@@ -125,7 +121,7 @@ void tst_PackagerTool::initTestCase()
chainOfTrust << devcaFile.readAll() << caFile.readAll();
QVERIFY(!chainOfTrust.at(0).isEmpty());
QVERIFY(!chainOfTrust.at(1).isEmpty());
- m_ai->setCACertificates(chainOfTrust);
+ m_pm->setCACertificates(chainOfTrust);
m_caFiles << devcaFile.fileName() << caFile.fileName();
@@ -139,7 +135,6 @@ void tst_PackagerTool::initTestCase()
void tst_PackagerTool::cleanup()
{
- recursiveOperation(pathTo("manifests"), safeRemove);
recursiveOperation(pathTo("internal-0"), safeRemove);
recursiveOperation(pathTo("documents-0"), safeRemove);
@@ -173,11 +168,11 @@ void tst_PackagerTool::test()
// no valid destination
QVERIFY(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), pathTo("test.appkg")), errorString));
- QVERIFY2(errorString.contains(qL1S("not a directory")), qPrintable(errorString));
+ QVERIFY2(errorString.contains(qL1S("is not a directory")), qPrintable(errorString));
// no valid info.yaml
QVERIFY(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), errorString));
- QVERIFY2(errorString.contains(qL1S("could not open file for reading")), qPrintable(errorString));
+ QVERIFY2(errorString.contains(qL1S("Cannot open for reading")), qPrintable(errorString));
// add an info.yaml file
createInfoYaml(tmp);
@@ -284,10 +279,10 @@ void tst_PackagerTool::brokenMetadata_data()
QTest::addColumn<QVariant>("yamlValue");
QTest::addColumn<QString>("errorString");
- QTest::newRow("missing-name") << "name" << QVariant("") << "~.*the 'name' field must not be empty";
- QTest::newRow("missing-runtime") << "runtime" << QVariant("") << "~.*the 'runtimeName' field must not be empty";
- QTest::newRow("missing-identifier") << "id" << QVariant("") << "~.*the identifier \\(\\) is not a valid application-id: must not be empty";
- QTest::newRow("missing-code") << "code" << QVariant("") << "~.*the 'code' field must not be empty";
+ QTest::newRow("missing-name") << qSL("name") << QVariant() << "~.*Required fields are missing: name.*";
+ QTest::newRow("missing-runtime") << qSL("runtime") << QVariant() << "~.*Required fields are missing: runtime";
+ QTest::newRow("missing-identifier") << qSL("id") << QVariant() << "~.*Required fields are missing: id";
+ QTest::newRow("missing-code") << qSL("code") << QVariant() << "~.*Required fields are missing: code";
}
void tst_PackagerTool::brokenMetadata()
@@ -305,7 +300,7 @@ void tst_PackagerTool::brokenMetadata()
// check if packaging actually fails with the expected error
QString error;
- QVERIFY(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), error));
+ QVERIFY2(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), error), qPrintable(error));
AM_CHECK_ERRORSTRING(error, errorString);
}
@@ -318,18 +313,18 @@ void tst_PackagerTool::iconFileName()
QTemporaryDir tmp;
QString errorString;
- createInfoYaml(tmp, "icon", "foo.bar");
+ createInfoYaml(tmp, qSL("icon"), qSL("foo.bar"));
createCode(tmp);
- createDummyFile(tmp, "foo.bar", "this-is-a-dummy-icon-file");
+ createDummyFile(tmp, qSL("foo.bar"), "this-is-a-dummy-icon-file");
QVERIFY2(packagerCheck(PackagingJob::create(pathTo("test-foobar-icon.appkg"), tmp.path()), errorString),
qPrintable(errorString));
// see if the package installs correctly
- m_ai->setAllowInstallationOfUnsignedPackages(true);
+ m_pm->setAllowInstallationOfUnsignedPackages(true);
installPackage(pathTo("test-foobar-icon.appkg"));
- m_ai->setAllowInstallationOfUnsignedPackages(false);
+ m_pm->setAllowInstallationOfUnsignedPackages(false);
QDir checkDir(pathTo("internal-0"));
QVERIFY(checkDir.cd(qSL("com.pelagicore.test")));
@@ -358,9 +353,17 @@ bool tst_PackagerTool::createInfoYaml(QTemporaryDir &tmp, const QString &changeF
"runtime: qml\n";
if (!changeField.isEmpty()) {
- QVector<QVariant> docs = QtYaml::variantDocumentsFromYaml(yaml);
+ QVector<QVariant> docs;
+ try {
+ docs = YamlParser::parseAllDocuments(yaml);
+ } catch (...) {
+ }
+
QVariantMap map = docs.at(1).toMap();
- map[changeField] = toValue;
+ if (!toValue.isValid())
+ map.remove(changeField);
+ else
+ map[changeField] = toValue;
yaml = QtYaml::yamlFromVariantDocuments({ docs.at(0), map });
}
@@ -387,23 +390,22 @@ void tst_PackagerTool::createDummyFile(QTemporaryDir &tmp, const QString &fileNa
auto written = code.write(data);
- QCOMPARE(written, (qint64)strlen(data));
+ QCOMPARE(written, static_cast<qint64>(strlen(data)));
}
void tst_PackagerTool::installPackage(const QString &filePath)
{
- QSignalSpy finishedSpy(m_ai, &ApplicationInstaller::taskFinished);
+ QSignalSpy finishedSpy(m_pm, &PackageManager::taskFinished);
- m_ai->setDevelopmentMode(true); // allow packages without store signature
+ m_pm->setDevelopmentMode(true); // allow packages without store signature
- QString taskId = m_ai->startPackageInstallation(qSL("internal-0"),
- QUrl::fromLocalFile(filePath));
- m_ai->acknowledgePackageInstallation(taskId);
+ QString taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(filePath));
+ m_pm->acknowledgePackageInstallation(taskId);
QVERIFY(finishedSpy.wait(2 * spyTimeout));
QCOMPARE(finishedSpy.first()[0].toString(), taskId);
- m_ai->setDevelopmentMode(false);
+ m_pm->setDevelopmentMode(false);
}
QTEST_GUILESS_MAIN(tst_PackagerTool)
diff --git a/tests/processreader/tst_processreader.cpp b/tests/processreader/tst_processreader.cpp
index 978770a0..1bfc0db0 100644
--- a/tests/processreader/tst_processreader.cpp
+++ b/tests/processreader/tst_processreader.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/tests/qml/configs/am-config.yaml b/tests/qml/configs/am-config.yaml
index 34a4c56a..5333dae3 100644
--- a/tests/qml/configs/am-config.yaml
+++ b/tests/qml/configs/am-config.yaml
@@ -3,16 +3,6 @@ formatType: am-configuration
---
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/apps"
- installedAppsManifestDir: "/tmp/am/manifests"
- appImageMountDir: "/tmp/am/image-mounts"
- database: "/tmp/am/apps.db"
-
-installationLocations:
-- id: "internal-0"
- installationPath: "/tmp/am/apps"
- documentPath: "/tmp/am/docs"
- mountPoint: "/tmp"
- isDefault: true
# Workaround for a crash in the mesa software renderer (llvmpipe)
runtimes:
diff --git a/tests/qml/configs/apps/test.configs.app/app.qml b/tests/qml/configs/apps/test.configs.app/app.qml
index 8ce11a63..402364ce 100644
--- a/tests/qml/configs/apps/test.configs.app/app.qml
+++ b/tests/qml/configs/apps/test.configs.app/app.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/configs/configs.pro b/tests/qml/configs/configs.pro
index 1ba0ab11..86604d5e 100644
--- a/tests/qml/configs/configs.pro
+++ b/tests/qml/configs/configs.pro
@@ -2,6 +2,7 @@ load(am-config)
AM_CONFIG = am-config.yaml
TEST_FILES = tst_configs.qml
+TEST_APPS = test.configs.app
TEST_CONFIGURATIONS = "--force-single-process" \
"--force-single-process --single-app $$_PRO_FILE_PWD_/apps/test.configs.app/info.yaml"
multi-process {
diff --git a/tests/qml/configs/tst_configs.qml b/tests/qml/configs/tst_configs.qml
index 0dac7b3b..7e92e89f 100644
--- a/tests/qml/configs/tst_configs.qml
+++ b/tests/qml/configs/tst_configs.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -90,7 +90,7 @@ TestCase {
function test_basic_ipc() {
compare(NotificationManager.count, 0);
compare(windowAddedSpy.count, 0);
- ApplicationManager.startApplication("test.configs.app");
+ verify(ApplicationManager.startApplication("test.configs.app"))
windowAddedSpy.wait();
compare(windowAddedSpy.count, 1);
var window = windowAddedSpy.signalArguments[0][0];
diff --git a/tests/qml/crash/am-config.yaml b/tests/qml/crash/am-config.yaml
index b9c17b5e..61b2bfb2 100644
--- a/tests/qml/crash/am-config.yaml
+++ b/tests/qml/crash/am-config.yaml
@@ -3,15 +3,6 @@ formatType: am-configuration
---
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/apps"
- installedAppsManifestDir: "/tmp/am-crash-test/manifests"
- appImageMountDir: "/tmp/am-crash-test/image-mounts"
- database: "/tmp/am-crash-test/apps.db"
-
-installationLocations:
-- id: "internal-0"
- installationPath: "/tmp/am/apps"
- documentPath: "/tmp/am/docs"
- mountPoint: "/tmp"
flags:
noUiWatchdog: yes
diff --git a/tests/qml/crash/apps/tld.test.crash/app.qml b/tests/qml/crash/apps/tld.test.crash/app.qml
index 262b0802..447b5bef 100644
--- a/tests/qml/crash/apps/tld.test.crash/app.qml
+++ b/tests/qml/crash/apps/tld.test.crash/app.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp b/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp
index 05e73934..0ed12064 100644
--- a/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp
+++ b/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h b/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h
index d8fabbf9..5d59d6ea 100644
--- a/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h
+++ b/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/tests/qml/crash/crash.pro b/tests/qml/crash/crash.pro
index 160c90af..b3bff364 100644
--- a/tests/qml/crash/crash.pro
+++ b/tests/qml/crash/crash.pro
@@ -1,4 +1,6 @@
AM_CONFIG = am-config.yaml
TEST_FILES = tst_crash.qml
+TEST_APPS = tld.test.crash
load(am-qml-testcase)
+
diff --git a/tests/qml/crash/tst_crash.qml b/tests/qml/crash/tst_crash.qml
index 8360652b..eacc66b3 100644
--- a/tests/qml/crash/tst_crash.qml
+++ b/tests/qml/crash/tst_crash.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/installer/am-config.yaml b/tests/qml/installer/am-config.yaml
index 03a59daa..d0e12789 100644
--- a/tests/qml/installer/am-config.yaml
+++ b/tests/qml/installer/am-config.yaml
@@ -3,16 +3,8 @@ formatType: am-configuration
---
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/apps"
- installedAppsManifestDir: "/tmp/am-installer-test/manifests"
- appImageMountDir: "/tmp/am-installer-test/image-mounts"
- database: "/tmp/am-installer-test/apps.db"
-
-installationLocations:
-- id: "internal-0"
- installationPath: "/tmp/am-installer-test/apps"
- documentPath: "/tmp/am-installer-test/docs"
- mountPoint: "/tmp"
- isDefault: true
+ installationDir: "/tmp/am-installer-test/apps"
+ documentDir: "/tmp/am-installer-test/docs"
flags:
noSecurity: yes
diff --git a/tests/qml/installer/apps/builtin.app/app1.qml b/tests/qml/installer/apps/hello-world.red/app1.qml
index c18b5421..a3c4b30f 100644
--- a/tests/qml/installer/apps/builtin.app/app1.qml
+++ b/tests/qml/installer/apps/hello-world.red/app1.qml
@@ -3,7 +3,7 @@
** Copyright (C) 2019 Luxoft Sweden AB
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/installer/apps/builtin.app/icon1.png b/tests/qml/installer/apps/hello-world.red/icon1.png
index c1397153..c1397153 100644
--- a/tests/qml/installer/apps/builtin.app/icon1.png
+++ b/tests/qml/installer/apps/hello-world.red/icon1.png
Binary files differ
diff --git a/tests/qml/installer/apps/builtin.app/info.yaml b/tests/qml/installer/apps/hello-world.red/info.yaml
index 9320306b..1b628d1e 100644
--- a/tests/qml/installer/apps/builtin.app/info.yaml
+++ b/tests/qml/installer/apps/hello-world.red/info.yaml
@@ -1,7 +1,7 @@
formatVersion: 1
formatType: am-application
---
-id: 'builtin.app'
+id: 'hello-world.red'
version: 'v1'
icon: 'icon1.png'
code: 'app1.qml'
diff --git a/tests/qml/installer/appv1.pkg b/tests/qml/installer/appv1.pkg
deleted file mode 100644
index 416cf018..00000000
--- a/tests/qml/installer/appv1.pkg
+++ /dev/null
Binary files differ
diff --git a/tests/qml/installer/appv2.pkg b/tests/qml/installer/appv2.pkg
deleted file mode 100644
index d3a15de5..00000000
--- a/tests/qml/installer/appv2.pkg
+++ /dev/null
Binary files differ
diff --git a/tests/qml/installer/builtinv2.pkg b/tests/qml/installer/builtinv2.pkg
deleted file mode 100644
index b32c2422..00000000
--- a/tests/qml/installer/builtinv2.pkg
+++ /dev/null
Binary files differ
diff --git a/tests/qml/installer/install-apps/appv1/info.yaml b/tests/qml/installer/install-apps/appv1/info.yaml
deleted file mode 100644
index 2c04ec5d..00000000
--- a/tests/qml/installer/install-apps/appv1/info.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-formatVersion: 1
-formatType: am-application
----
-id: 'test.install.app'
-version: 'v1'
-icon: 'icon1.png'
-code: 'app1.qml'
-runtime: 'qml'
-name:
- en: 'Installation Test App Version 1'
diff --git a/tests/qml/installer/install-apps/appv2/info.yaml b/tests/qml/installer/install-apps/appv2/info.yaml
deleted file mode 100644
index f7e2f96a..00000000
--- a/tests/qml/installer/install-apps/appv2/info.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-formatVersion: 1
-formatType: am-application
----
-id: 'test.install.app'
-version: 'v2'
-icon: 'icon2.png'
-code: 'app2.qml'
-runtime: 'qml'
-name:
- en: 'Installation Test App Version 2'
diff --git a/tests/qml/installer/install-apps/builtinv2/icon2.png b/tests/qml/installer/install-apps/builtinv2/icon2.png
deleted file mode 100644
index c1397153..00000000
--- a/tests/qml/installer/install-apps/builtinv2/icon2.png
+++ /dev/null
Binary files differ
diff --git a/tests/qml/installer/install-apps/builtinv2/info.yaml b/tests/qml/installer/install-apps/builtinv2/info.yaml
deleted file mode 100644
index 3e90f151..00000000
--- a/tests/qml/installer/install-apps/builtinv2/info.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-formatVersion: 1
-formatType: am-application
----
-id: 'builtin.app'
-version: 'v2'
-icon: 'icon2.png'
-code: 'app2.qml'
-runtime: 'qml'
-name:
- en: 'Builtin Installation Test App v2'
diff --git a/tests/qml/installer/installer.pro b/tests/qml/installer/installer.pro
index d85f1607..2adfb2a4 100644
--- a/tests/qml/installer/installer.pro
+++ b/tests/qml/installer/installer.pro
@@ -1,6 +1,6 @@
AM_CONFIG = am-config.yaml
TEST_FILES = tst_installer.qml
-FILES = appv1.pkg appv2.pkg
+AM_TESTDATA_DIR=\"$$PWD/../../data/\"
load(am-qml-testcase)
diff --git a/tests/qml/installer/tst_installer.qml b/tests/qml/installer/tst_installer.qml
index 01bb7a32..dced0938 100644
--- a/tests/qml/installer/tst_installer.qml
+++ b/tests/qml/installer/tst_installer.qml
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -54,25 +55,25 @@ TestCase {
SignalSpy {
id: taskFinishedSpy
- target: ApplicationInstaller
+ target: PackageManager
signalName: "taskFinished"
}
SignalSpy {
id: taskFailedSpy
- target: ApplicationInstaller
+ target: PackageManager
signalName: "taskFailed"
}
SignalSpy {
id: taskStateChangedSpy
- target: ApplicationInstaller
+ target: PackageManager
signalName: "taskStateChanged"
}
SignalSpy {
id: taskRequestingInstallationAcknowledgeSpy
- target: ApplicationInstaller
+ target: PackageManager
signalName: "taskRequestingInstallationAcknowledge"
}
@@ -85,31 +86,35 @@ TestCase {
function init() {
// Remove previous installations
- if (ApplicationInstaller.removePackage("test.install.app", false, true)) {
- taskFinishedSpy.wait(spyTimeout);
- compare(taskFinishedSpy.count, 1);
- taskFinishedSpy.clear();
+
+ for (var pkg of [ "hello-world.red", "com.pelagicore.test" ]) {
+ if (PackageManager.removePackage(pkg, false, true)) {
+ taskFinishedSpy.wait(spyTimeout);
+ compare(taskFinishedSpy.count, 1);
+ taskFinishedSpy.clear();
+ }
}
}
- function test_states() {
- ApplicationManager.applicationAdded.connect(function(id) {
- var app = ApplicationManager.application(id);
- stateList.push(app.state);
- app.stateChanged.connect(function(state) {
- compare(state, app.state);
- stateList.push(state);
- });
- });
+ function test_1states() {
+ PackageManager.packageAdded.connect(function(pkgId) {
+ var pkg = PackageManager.package(pkgId);
+ stateList.push(pkg.state)
+ pkg.stateChanged.connect(function(state) {
+ compare(state, pkg.state)
+ stateList.push(state)
+ })
+ })
taskStateChangedSpy.clear();
- var id = ApplicationInstaller.startPackageInstallation("internal-0", "appv1.pkg");
+ var id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR
+ + "/packages/test-dev-signed.appkg")
taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout);
compare(taskRequestingInstallationAcknowledgeSpy.count, 1);
compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id);
- var appId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id
+ var pkgId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id
taskRequestingInstallationAcknowledgeSpy.clear();
- ApplicationInstaller.acknowledgePackageInstallation(id);
+ PackageManager.acknowledgePackageInstallation(id);
if (!taskFinishedSpy.count)
taskFinishedSpy.wait(spyTimeout);
@@ -117,131 +122,137 @@ TestCase {
taskFinishedSpy.clear();
compare(stateList.length, 2);
- compare(stateList[0], ApplicationObject.BeingInstalled);
- compare(stateList[1], ApplicationObject.Installed);
- stateList = [];
+ compare(stateList[0], PackageObject.BeingInstalled)
+ compare(stateList[1], PackageObject.Installed)
+ stateList = []
- id = ApplicationInstaller.startPackageInstallation("internal-0", "appv2.pkg")
+ id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR
+ + "/packages/test-update-dev-signed.appkg")
taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout);
compare(taskRequestingInstallationAcknowledgeSpy.count, 1);
compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id);
taskRequestingInstallationAcknowledgeSpy.clear();
- ApplicationInstaller.acknowledgePackageInstallation(id);
+ PackageManager.acknowledgePackageInstallation(id);
taskFinishedSpy.wait(spyTimeout);
compare(taskFinishedSpy.count, 1);
taskFinishedSpy.clear();
- compare(stateList[0], ApplicationObject.BeingUpdated);
- compare(stateList[1], ApplicationObject.Installed);
- stateList = [];
+ compare(stateList[0], PackageObject.BeingUpdated)
+ compare(stateList[1], PackageObject.Installed)
+ stateList = []
- id = ApplicationInstaller.removePackage(appId, false, false);
+ id = PackageManager.removePackage(pkgId, false, false);
taskFinishedSpy.wait(spyTimeout);
compare(taskFinishedSpy.count, 1);
taskFinishedSpy.clear();
- compare(stateList[0], ApplicationObject.BeingRemoved);
- stateList = [];
+ compare(stateList[0], PackageObject.BeingRemoved)
+ stateList = []
// Cannot compare app.state any more, since app might already be dead
verify(taskStateChangedSpy.count > 10);
- var taskStates = [ ApplicationInstaller.Executing,
- ApplicationInstaller.AwaitingAcknowledge,
- ApplicationInstaller.Installing,
- ApplicationInstaller.CleaningUp,
- ApplicationInstaller.Finished,
- ApplicationInstaller.Executing,
- ApplicationInstaller.AwaitingAcknowledge,
- ApplicationInstaller.Installing,
- ApplicationInstaller.CleaningUp,
- ApplicationInstaller.Finished,
- ApplicationInstaller.Executing ]
+ var taskStates = [ PackageManager.Executing,
+ PackageManager.AwaitingAcknowledge,
+ PackageManager.Installing,
+ PackageManager.CleaningUp,
+ PackageManager.Finished,
+ PackageManager.Executing,
+ PackageManager.AwaitingAcknowledge,
+ PackageManager.Installing,
+ PackageManager.CleaningUp,
+ PackageManager.Finished,
+ PackageManager.Executing ]
for (var i = 0; i < taskStates.length; i++)
compare(taskStateChangedSpy.signalArguments[i][1], taskStates[i], "- index: " + i);
}
- function test_cancel_update() {
- var id = ApplicationInstaller.startPackageInstallation("internal-0", "appv1.pkg")
+ function test_2cancel_update() {
+ var id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR
+ + "/packages/test-dev-signed.appkg")
taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout);
compare(taskRequestingInstallationAcknowledgeSpy.count, 1);
compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id);
- var appId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id
- compare(appId, "test.install.app");
+ var pkgId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id
+ compare(pkgId, "com.pelagicore.test");
taskRequestingInstallationAcknowledgeSpy.clear();
- ApplicationInstaller.acknowledgePackageInstallation(id);
+ PackageManager.acknowledgePackageInstallation(id);
taskFinishedSpy.wait(spyTimeout);
taskFinishedSpy.clear();
- var app = ApplicationManager.application(appId);
- compare(app.icon.toString().slice(-9), "icon1.png")
- compare(app.version, "v1");
+ var pkg = PackageManager.package(pkgId);
+ compare(pkg.version, "1.0");
- id = ApplicationInstaller.startPackageInstallation("internal-0", "appv2.pkg")
+ id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR
+ + "/packages/test-update-dev-signed.appkg")
taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout);
- appId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id
- compare(appId, "test.install.app");
+ pkgId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id
+ compare(pkgId, "com.pelagicore.test");
taskRequestingInstallationAcknowledgeSpy.clear();
- ApplicationInstaller.cancelTask(id);
+ PackageManager.cancelTask(id);
taskFailedSpy.wait(spyTimeout);
taskFailedSpy.clear();
- compare(app.icon.toString().slice(-9), "icon1.png")
- compare(app.version, "v1");
+ compare(pkg.version, "1.0");
}
- function test_cancel_builtin_update() {
+ function test_3cancel_builtin_update() {
taskStateChangedSpy.clear()
- var app = ApplicationManager.application("builtin.app");
- verify(app.builtIn);
- compare(app.icon.toString().slice(-9), "icon1.png")
- compare(app.version, "v1");
+ var pkg = PackageManager.package("hello-world.red");
+ verify(pkg.builtIn);
+ compare(pkg.icon.toString().slice(-9), "icon1.png")
+ compare(pkg.version, "v1");
- var id = ApplicationInstaller.startPackageInstallation("internal-0", "builtinv2.pkg")
+ var id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR
+ + "/packages/hello-world.red.appkg")
taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout);
compare(taskRequestingInstallationAcknowledgeSpy.count, 1);
compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id);
taskRequestingInstallationAcknowledgeSpy.clear();
- ApplicationInstaller.cancelTask(id);
+ PackageManager.cancelTask(id);
taskFailedSpy.wait(spyTimeout);
taskFailedSpy.clear();
- verify(app.builtIn);
- compare(app.icon.toString().slice(-9), "icon1.png")
- compare(app.version, "v1");
+ verify(pkg.builtIn);
+ compare(pkg.icon.toString().slice(-9), "icon1.png")
+ compare(pkg.version, "v1");
}
- function test_builtin_update_downgrade() {
+ function test_4builtin_update_downgrade() {
taskStateChangedSpy.clear()
- var id = ApplicationInstaller.startPackageInstallation("internal-0", "builtinv2.pkg")
+
+ var id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR
+ + "/packages/hello-world.red.appkg")
taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout);
compare(taskRequestingInstallationAcknowledgeSpy.count, 1);
compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id);
taskRequestingInstallationAcknowledgeSpy.clear();
- ApplicationInstaller.acknowledgePackageInstallation(id);
+ PackageManager.acknowledgePackageInstallation(id);
taskFinishedSpy.wait(spyTimeout);
- compare(ApplicationManager.get("builtin.app").version, "v2");
+ var pkg = PackageManager.package("hello-world.red")
+ compare(pkg.version, "red");
taskFinishedSpy.clear();
applicationChangedSpy.clear();
// remvove is a downgrade
- verify(ApplicationInstaller.removePackage("builtin.app", false, true));
+ verify(pkg.builtIn)
+ verify(pkg.builtInHasRemovableUpdate)
+ verify(PackageManager.removePackage("hello-world.red", false, true));
taskFinishedSpy.wait(spyTimeout);
compare(taskFinishedSpy.count, 1);
taskFinishedSpy.clear();
- compare(applicationChangedSpy.count, 5);
- compare(applicationChangedSpy.signalArguments[3][0], "builtin.app");
- compare(applicationChangedSpy.signalArguments[3][1], []);
- compare(applicationChangedSpy.signalArguments[4][1], ["isBlocked"]);
+ compare(applicationChangedSpy.count, 3);
+ compare(applicationChangedSpy.signalArguments[0][0], "hello-world.red");
+ compare(applicationChangedSpy.signalArguments[0][1], ["isBlocked"]);
+ compare(applicationChangedSpy.signalArguments[2][1], []);
- var appmodel = ApplicationManager.get("builtin.app");
- verify(!appmodel.isBlocked);
- compare(appmodel.version, "v1");
+ verify(!pkg.blocked)
+ compare(pkg.version, "v1");
}
}
diff --git a/tests/qml/intents/am-config.yaml b/tests/qml/intents/am-config.yaml
index 6c4957a1..1667c123 100644
--- a/tests/qml/intents/am-config.yaml
+++ b/tests/qml/intents/am-config.yaml
@@ -20,4 +20,4 @@ intents:
disambiguation: 1000
startApplication: 1000
replyFromApplication: 1000
- requestToSystem: 2000
+ replyFromSystem: 2000
diff --git a/tests/qml/intents/apps/intents1/intents1.qml b/tests/qml/intents/apps/intents1/intents1.qml
index 560cdb3a..eb53a84c 100644
--- a/tests/qml/intents/apps/intents1/intents1.qml
+++ b/tests/qml/intents/apps/intents1/intents1.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/intents/apps/intents2/intents2.qml b/tests/qml/intents/apps/intents2/intents2.qml
index 7c989a17..d77ac506 100644
--- a/tests/qml/intents/apps/intents2/intents2.qml
+++ b/tests/qml/intents/apps/intents2/intents2.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/intents/intents.pro b/tests/qml/intents/intents.pro
index ae6415a6..797f96e8 100644
--- a/tests/qml/intents/intents.pro
+++ b/tests/qml/intents/intents.pro
@@ -1,7 +1,5 @@
AM_CONFIG = am-config.yaml
TEST_FILES = tst_intents.qml
-
-APPS = intents1 intents2 cannot-start
-for (app, APPS): OTHER_FILES += apps/$${app}/*.yaml apps/$${app}/*.qml apps/$${app}/*.png
+TEST_APPS = intents1 intents2 cannot-start
load(am-qml-testcase)
diff --git a/tests/qml/intents/tst_intents.qml b/tests/qml/intents/tst_intents.qml
index 9ab11a7a..3ac6a03b 100644
--- a/tests/qml/intents/tst_intents.qml
+++ b/tests/qml/intents/tst_intents.qml
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -74,66 +75,51 @@ TestCase {
signalName: "replyReceived"
}
- function test_intent_gadget() {
- var allIntents = IntentServer.intentList
- verify(allIntents.length > 0)
+ function test_intent_object() {
+ verify(IntentServer.count> 0)
// test intent properties
- var intent = IntentServer.find("both", "intents1")
- verify(intent.valid)
+ var intent = IntentServer.applicationIntent("both", "intents1")
+ verify(intent)
compare(intent.intentId, "both")
compare(intent.applicationId, "intents1")
- compare(intent.visibility, Intent.Public)
+ compare(intent.visibility, IntentObject.Public)
compare(intent.requiredCapabilities, [])
compare(intent.parameterMatch, {})
- // test comparison operators
- var pos = allIntents.indexOf(intent)
- verify(pos >= 0)
- var intent1 = IntentServer.find("both", "intents1")
- var intent2 = IntentServer.find("both", "intents2")
- verify(intent1.valid)
- verify(intent2.valid)
- verify(intent1 == intent)
- verify(intent1 === intent)
- verify(intent1 != intent2)
- verify(intent1 !== intent2)
- verify(intent1 < intent2)
- verify(intent2 > intent1)
-
- verify(!IntentServer.find("both", "intents3").valid)
- verify(!IntentServer.find("bothx", "intents1").valid)
- verify(!IntentServer.find("both", "").valid)
- verify(!IntentServer.find("", "intents1").valid)
- verify(!IntentServer.find("", "").valid)
+ verify(!IntentServer.applicationIntent("both", "intents3"))
+ verify(!IntentServer.applicationIntent("bothx", "intents1"))
+ verify(!IntentServer.applicationIntent("both", ""))
+ verify(!IntentServer.applicationIntent("", "intents1"))
+ verify(!IntentServer.applicationIntent("", ""))
}
function test_match() {
// first, check the matching on the server API
- var intent = IntentServer.find("match", "intents1")
- verify(!intent.valid)
- intent = IntentServer.find("match", "intents1", matchParams)
- verify(intent.valid)
+ var intent = IntentServer.applicationIntent("match", "intents1")
+ verify(!intent)
+ intent = IntentServer.applicationIntent("match", "intents1", matchParams)
+ verify(intent)
compare(intent.parameterMatch, { "list": [ "a", "b" ], "int": 42, "string": "^foo_.*_bar$", "complex": { "a": 1 } })
var params = matchParams
params.list = "c"
- verify(!IntentServer.find("match", "intents1", params).valid)
+ verify(!IntentServer.applicationIntent("match", "intents1", params))
params.list = "b"
- verify(IntentServer.find("match", "intents1", params).valid)
+ verify(IntentServer.applicationIntent("match", "intents1", params))
params.int = 2
- verify(!IntentServer.find("match", "intents1", params).valid)
+ verify(!IntentServer.applicationIntent("match", "intents1", params))
params.int = 42
params.string = "foo"
- verify(!IntentServer.find("match", "intents1", params).valid)
+ verify(!IntentServer.applicationIntent("match", "intents1", params))
params.string = "foo_test_bar"
- verify(IntentServer.find("match", "intents1", params).valid)
+ verify(IntentServer.applicationIntent("match", "intents1", params))
params.complex = "string"
- verify(!IntentServer.find("match", "intents1", params).valid)
+ verify(!IntentServer.applicationIntent("match", "intents1", params))
params.complex = matchParams.complex
}
@@ -241,8 +227,9 @@ TestCase {
break
case "acknowledge":
var intent = possibleIntents[0]
- if (data.acknowledgeIntentId)
- intent = IntentServer.find(data.acknowledgeIntentId, possibleIntents[0].applicationId)
+ if (data.acknowledgeIntentId) {
+ intent = IntentServer.applicationIntent(data.acknowledgeIntentId, possibleIntents[0].applicationId)
+ }
IntentServer.acknowledgeDisambiguationRequest(disambiguateSpy.signalArguments[0][0], intent)
break
}
diff --git a/tests/qml/lifecycle/am-config.yaml b/tests/qml/lifecycle/am-config.yaml
index b9c17b5e..61b2bfb2 100644
--- a/tests/qml/lifecycle/am-config.yaml
+++ b/tests/qml/lifecycle/am-config.yaml
@@ -3,15 +3,6 @@ formatType: am-configuration
---
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/apps"
- installedAppsManifestDir: "/tmp/am-crash-test/manifests"
- appImageMountDir: "/tmp/am-crash-test/image-mounts"
- database: "/tmp/am-crash-test/apps.db"
-
-installationLocations:
-- id: "internal-0"
- installationPath: "/tmp/am/apps"
- documentPath: "/tmp/am/docs"
- mountPoint: "/tmp"
flags:
noUiWatchdog: yes
diff --git a/tests/qml/qml.pro b/tests/qml/qml.pro
index d6a064f6..83cca142 100644
--- a/tests/qml/qml.pro
+++ b/tests/qml/qml.pro
@@ -15,4 +15,5 @@ SUBDIRS = \
crash/apps/tld.test.crash/terminator2 \
crash \
configs \
- lifecycle
+ lifecycle \
+ resources
diff --git a/tests/qml/quicklaunch/am-config.yaml b/tests/qml/quicklaunch/am-config.yaml
index cb9e528a..e8de3d00 100644
--- a/tests/qml/quicklaunch/am-config.yaml
+++ b/tests/qml/quicklaunch/am-config.yaml
@@ -3,16 +3,6 @@ formatType: am-configuration
---
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/apps"
- installedAppsManifestDir: "/tmp/am-quicklaunch-test/manifests"
- appImageMountDir: "/tmp/am-quicklaunch-test/image-mounts"
- database: "/tmp/am-quicklaunch-test/apps.db"
-
-installationLocations:
-- id: "internal-0"
- installationPath: "/tmp/am/apps"
- documentPath: "/tmp/am/docs"
- mountPoint: "/tmp"
- isDefault: true
quicklaunch:
runtimesPerContainer: 2
diff --git a/tests/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml b/tests/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml
index 1c203d4f..9defde81 100644
--- a/tests/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml
+++ b/tests/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/quicklaunch/quicklaunch.pro b/tests/qml/quicklaunch/quicklaunch.pro
index 4c6b8f74..2d990a4b 100644
--- a/tests/qml/quicklaunch/quicklaunch.pro
+++ b/tests/qml/quicklaunch/quicklaunch.pro
@@ -1,4 +1,5 @@
AM_CONFIG = am-config.yaml
TEST_FILES = tst_quicklaunch.qml
+TEST_APPS = tld.test.quicklaunch
load(am-qml-testcase)
diff --git a/tests/qml/quicklaunch/tst_quicklaunch.qml b/tests/qml/quicklaunch/tst_quicklaunch.qml
index b840e691..1e4e4e5d 100644
--- a/tests/qml/quicklaunch/tst_quicklaunch.qml
+++ b/tests/qml/quicklaunch/tst_quicklaunch.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/resources/am-config.yaml b/tests/qml/resources/am-config.yaml
new file mode 100644
index 00000000..b846a005
--- /dev/null
+++ b/tests/qml/resources/am-config.yaml
@@ -0,0 +1,22 @@
+formatVersion: 1
+formatType: am-configuration
+---
+applications:
+ builtinAppsManifestDir: "${CONFIG_PWD}/apps"
+ installationDir: "/tmp/am-resource-test/apps"
+
+quicklaunch:
+ runtimesPerContainer: 1
+ idleLoad: 1.0
+
+runtimes:
+ qml:
+ resources: "${CONFIG_PWD}/appcommon/appcommonfile.rcc"
+ importPaths: "qrc:/appcommon/qml"
+ quicklaunchQml: "qrc:/appcommon/Quicklaunch.qml"
+
+ui:
+ importPaths: "qrc:///qml"
+ resources:
+ - "${CONFIG_PWD}/systemuifile.rcc"
+ - "${CONFIG_PWD}/systemuiplugin" # libsystemuiplugin.so would only work on Linux
diff --git a/tests/qml/resources/appcommon/Quicklaunch.qml b/tests/qml/resources/appcommon/Quicklaunch.qml
new file mode 100644
index 00000000..a8998d0e
--- /dev/null
+++ b/tests/qml/resources/appcommon/Quicklaunch.qml
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.11
+import common 1.0
+
+CommonObj {
+ Component.onCompleted: console.info("Quicklaunch - meaning: " + meaning);
+}
diff --git a/tests/qml/resources/appcommon/appcommon.pro b/tests/qml/resources/appcommon/appcommon.pro
new file mode 100644
index 00000000..47028775
--- /dev/null
+++ b/tests/qml/resources/appcommon/appcommon.pro
@@ -0,0 +1,7 @@
+TEMPLATE = aux
+
+OTHER_FILES += Quicklaunch.qml \
+ qml/common/CommonObj.qml
+
+RESOURCE_SOURCE = appcommonfile.qrc
+load(generate-resource)
diff --git a/tests/qml/resources/appcommon/appcommonfile.qrc b/tests/qml/resources/appcommon/appcommonfile.qrc
new file mode 100644
index 00000000..4dc15f85
--- /dev/null
+++ b/tests/qml/resources/appcommon/appcommonfile.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="appcommon">
+ <file>qml/common/CommonObj.qml</file>
+ <file>qml/common/qmldir</file>
+ <file>Quicklaunch.qml</file>
+</qresource>
+</RCC>
diff --git a/tests/qml/resources/appcommon/qml/common/CommonObj.qml b/tests/qml/resources/appcommon/qml/common/CommonObj.qml
new file mode 100644
index 00000000..ff1fdcf7
--- /dev/null
+++ b/tests/qml/resources/appcommon/qml/common/CommonObj.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.11
+
+QtObject {
+ property int meaning: 42
+}
diff --git a/tests/qml/resources/appcommon/qml/common/qmldir b/tests/qml/resources/appcommon/qml/common/qmldir
new file mode 100644
index 00000000..5458b257
--- /dev/null
+++ b/tests/qml/resources/appcommon/qml/common/qmldir
@@ -0,0 +1,2 @@
+module common
+CommonObj 1.0 CommonObj.qml
diff --git a/tests/qml/resources/apps/app1/app1.pro b/tests/qml/resources/apps/app1/app1.pro
new file mode 100644
index 00000000..cbbb4758
--- /dev/null
+++ b/tests/qml/resources/apps/app1/app1.pro
@@ -0,0 +1,11 @@
+TEMPLATE = lib
+TARGET = app1plugin
+CONFIG += plugin
+RESOURCES = app1plugin.qrc
+
+RESOURCE_SOURCE = app1file.qrc
+load(generate-resource)
+
+OTHER_FILES += \
+ info.yaml \
+ icon.png
diff --git a/tests/qml/resources/apps/app1/app1.qml b/tests/qml/resources/apps/app1/app1.qml
new file mode 100644
index 00000000..9ab04279
--- /dev/null
+++ b/tests/qml/resources/apps/app1/app1.qml
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtApplicationManager.Application 2.0
+import forms 1.0
+
+ApplicationManagerWindow {
+ YellowRect {}
+ AquaRect {}
+}
diff --git a/tests/qml/resources/apps/app1/app1file.qrc b/tests/qml/resources/apps/app1/app1file.qrc
new file mode 100644
index 00000000..6c958e89
--- /dev/null
+++ b/tests/qml/resources/apps/app1/app1file.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/app1">
+ <file>app1.qml</file>
+ <file>qml/forms/YellowRect.qml</file>
+ <file>qml/forms/qmldir</file>
+</qresource>
+</RCC>
diff --git a/tests/qml/resources/apps/app1/app1plugin.qrc b/tests/qml/resources/apps/app1/app1plugin.qrc
new file mode 100644
index 00000000..6c4e2ae3
--- /dev/null
+++ b/tests/qml/resources/apps/app1/app1plugin.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/app1">
+ <file>qml/forms/AquaRect.qml</file>
+</qresource>
+</RCC>
diff --git a/tests/qml/installer/install-apps/appv1/icon1.png b/tests/qml/resources/apps/app1/icon.png
index c1397153..c1397153 100644
--- a/tests/qml/installer/install-apps/appv1/icon1.png
+++ b/tests/qml/resources/apps/app1/icon.png
Binary files differ
diff --git a/tests/qml/resources/apps/app1/info.yaml b/tests/qml/resources/apps/app1/info.yaml
new file mode 100644
index 00000000..a5287f2c
--- /dev/null
+++ b/tests/qml/resources/apps/app1/info.yaml
@@ -0,0 +1,17 @@
+formatVersion: 1
+formatType: am-package
+---
+id: 'app1'
+icon: 'icon.png'
+name:
+ en: 'Resource Test App 1'
+
+applications:
+ - id: 'app1'
+ code: 'qrc:///app1/app1.qml'
+ runtime: 'qml'
+ runtimeParameters:
+ importPaths: "qrc:///app1/qml"
+ resources:
+ - app1file.rcc
+ - app1plugin # libapp1plugin.so would only work on Linux
diff --git a/tests/qml/installer/install-apps/appv2/app2.qml b/tests/qml/resources/apps/app1/qml/forms/AquaRect.qml
index 0e1798c3..8bd906a6 100644
--- a/tests/qml/installer/install-apps/appv2/app2.qml
+++ b/tests/qml/resources/apps/app1/qml/forms/AquaRect.qml
@@ -3,7 +3,7 @@
** Copyright (C) 2019 Luxoft Sweden AB
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -39,6 +39,8 @@
**
****************************************************************************/
-import QtQuick 2.4
+import QtQuick 2.11
-Rectangle {}
+Rectangle {
+ color: "aqua"
+}
diff --git a/tests/qml/resources/apps/app1/qml/forms/YellowRect.qml b/tests/qml/resources/apps/app1/qml/forms/YellowRect.qml
new file mode 100644
index 00000000..a4b5d9cb
--- /dev/null
+++ b/tests/qml/resources/apps/app1/qml/forms/YellowRect.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.11
+
+Rectangle {
+ color: "yellow"
+}
diff --git a/tests/qml/resources/apps/app1/qml/forms/qmldir b/tests/qml/resources/apps/app1/qml/forms/qmldir
new file mode 100644
index 00000000..12a5506b
--- /dev/null
+++ b/tests/qml/resources/apps/app1/qml/forms/qmldir
@@ -0,0 +1,4 @@
+module forms
+YellowRect 1.0 qrc:///app1/qml/forms/YellowRect.qml
+# :/app1/qml/forms/YellowRect.qml would not work
+AquaRect 1.0 AquaRect.qml
diff --git a/tests/qml/installer/install-apps/appv1/app1.qml b/tests/qml/resources/apps/app2/BlueRect.qml
index 4934be54..151dd1eb 100644
--- a/tests/qml/installer/install-apps/appv1/app1.qml
+++ b/tests/qml/resources/apps/app2/BlueRect.qml
@@ -3,7 +3,7 @@
** Copyright (C) 2019 Luxoft Sweden AB
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -39,6 +39,8 @@
**
****************************************************************************/
-import QtQuick 2.4
+import QtQuick 2.11
-Item {}
+Rectangle {
+ color: "blue"
+}
diff --git a/tests/qml/resources/apps/app2/app2.pro b/tests/qml/resources/apps/app2/app2.pro
new file mode 100644
index 00000000..7a5190df
--- /dev/null
+++ b/tests/qml/resources/apps/app2/app2.pro
@@ -0,0 +1,8 @@
+TEMPLATE = aux
+
+RESOURCE_SOURCE = app2.qrc
+load(generate-resource)
+
+OTHER_FILES += \
+ info.yaml \
+ icon.png
diff --git a/tests/qml/resources/apps/app2/app2.qml b/tests/qml/resources/apps/app2/app2.qml
new file mode 100644
index 00000000..25663cef
--- /dev/null
+++ b/tests/qml/resources/apps/app2/app2.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtApplicationManager.Application 2.0
+import QtQuick 2.11
+import appwidgets 1.0
+import common 1.0
+
+ApplicationManagerWindow {
+ CommonObj { id: common }
+ BlueRect { }
+ GreenRect { }
+
+ Timer {
+ running: true
+ interval: 20
+ onTriggered: setWindowProperty("meaning", common.meaning);
+ }
+}
diff --git a/tests/qml/resources/apps/app2/app2.qrc b/tests/qml/resources/apps/app2/app2.qrc
new file mode 100644
index 00000000..80bc560c
--- /dev/null
+++ b/tests/qml/resources/apps/app2/app2.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>app2.qml</file>
+ <file>BlueRect.qml</file>
+</qresource>
+</RCC>
diff --git a/tests/qml/installer/install-apps/appv2/icon2.png b/tests/qml/resources/apps/app2/icon.png
index c1397153..c1397153 100644
--- a/tests/qml/installer/install-apps/appv2/icon2.png
+++ b/tests/qml/resources/apps/app2/icon.png
Binary files differ
diff --git a/tests/qml/resources/apps/app2/info.yaml b/tests/qml/resources/apps/app2/info.yaml
new file mode 100644
index 00000000..6eda565b
--- /dev/null
+++ b/tests/qml/resources/apps/app2/info.yaml
@@ -0,0 +1,15 @@
+formatVersion: 1
+formatType: am-package
+---
+id: 'app2'
+icon: 'icon.png'
+name:
+ en: 'Resource Test App 2'
+
+applications:
+ - id: 'app2'
+ code: ':/app2.qml'
+ runtime: 'qml'
+ runtimeParameters:
+ importPaths: "qml"
+ resources: "app2.rcc"
diff --git a/tests/qml/resources/apps/app2/qml/appwidgets/GreenRect.qml b/tests/qml/resources/apps/app2/qml/appwidgets/GreenRect.qml
new file mode 100644
index 00000000..d727e11e
--- /dev/null
+++ b/tests/qml/resources/apps/app2/qml/appwidgets/GreenRect.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.11
+
+Rectangle {
+ color: "green"
+}
diff --git a/tests/qml/resources/apps/app2/qml/appwidgets/qmldir b/tests/qml/resources/apps/app2/qml/appwidgets/qmldir
new file mode 100644
index 00000000..a158bf25
--- /dev/null
+++ b/tests/qml/resources/apps/app2/qml/appwidgets/qmldir
@@ -0,0 +1,2 @@
+module appwidgets
+GreenRect 1.0 GreenRect.qml
diff --git a/tests/qml/resources/qml/widgets/MagentaRect.qml b/tests/qml/resources/qml/widgets/MagentaRect.qml
new file mode 100644
index 00000000..a90cf23b
--- /dev/null
+++ b/tests/qml/resources/qml/widgets/MagentaRect.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.11
+
+Rectangle {
+ color: "magenta"
+}
diff --git a/tests/qml/installer/install-apps/builtinv2/app2.qml b/tests/qml/resources/qml/widgets/RedRect.qml
index b65b03ce..b22b895b 100644
--- a/tests/qml/installer/install-apps/builtinv2/app2.qml
+++ b/tests/qml/resources/qml/widgets/RedRect.qml
@@ -3,7 +3,7 @@
** Copyright (C) 2019 Luxoft Sweden AB
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -39,7 +39,7 @@
**
****************************************************************************/
-import QtQuick 2.4
+import QtQuick 2.11
Rectangle {
color: "red"
diff --git a/tests/qml/resources/qml/widgets/qmldir b/tests/qml/resources/qml/widgets/qmldir
new file mode 100644
index 00000000..be36132a
--- /dev/null
+++ b/tests/qml/resources/qml/widgets/qmldir
@@ -0,0 +1,3 @@
+module widgets
+RedRect 1.0 RedRect.qml
+MagentaRect 1.0 MagentaRect.qml
diff --git a/tests/qml/resources/resources.pro b/tests/qml/resources/resources.pro
new file mode 100644
index 00000000..6da64f00
--- /dev/null
+++ b/tests/qml/resources/resources.pro
@@ -0,0 +1,5 @@
+TEMPLATE = subdirs
+SUBDIRS = test.pro \
+ appcommon \
+ apps/app1 \
+ apps/app2
diff --git a/tests/qml/resources/systemuifile.qrc b/tests/qml/resources/systemuifile.qrc
new file mode 100644
index 00000000..ce48e1a4
--- /dev/null
+++ b/tests/qml/resources/systemuifile.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>qml/widgets/RedRect.qml</file>
+ <file>qml/widgets/qmldir</file>
+</qresource>
+</RCC>
diff --git a/tests/qml/resources/systemuiplugin.qrc b/tests/qml/resources/systemuiplugin.qrc
new file mode 100644
index 00000000..7fe63a54
--- /dev/null
+++ b/tests/qml/resources/systemuiplugin.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>qml/widgets/MagentaRect.qml</file>
+</qresource>
+</RCC>
diff --git a/tests/qml/resources/test.pro b/tests/qml/resources/test.pro
new file mode 100644
index 00000000..fd145a2e
--- /dev/null
+++ b/tests/qml/resources/test.pro
@@ -0,0 +1,18 @@
+AM_CONFIG = am-config.yaml
+TEST_FILES = tst_resource.qml
+TEST_APPS = app1 app2
+
+DIRECTORIES = apps/app2/qml
+FILES = am-config.yaml \
+ apps/app1/icon.png apps/app1/info.yaml \
+ apps/app2/icon.png apps/app2/info.yaml
+DESTDIR = $$OUT_PWD
+load(am-qml-testcase)
+
+RESOURCE_SOURCE = systemuifile.qrc
+load(generate-resource)
+
+TEMPLATE = lib
+TARGET = systemuiplugin
+CONFIG += plugin
+RESOURCES = systemuiplugin.qrc
diff --git a/tests/qml/resources/tst_resource.qml b/tests/qml/resources/tst_resource.qml
new file mode 100644
index 00000000..36b47dfb
--- /dev/null
+++ b/tests/qml/resources/tst_resource.qml
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.11
+import QtTest 1.0
+import QtApplicationManager.SystemUI 2.0
+import widgets 1.0
+
+TestCase {
+ id: testCase
+ when: windowShown
+ name: "ResourceTest"
+
+ RedRect {}
+ MagentaRect {}
+
+ SignalSpy {
+        id: runStateChangedSpy
+        target: ApplicationManager
+        signalName: "applicationRunStateChanged"
+    }
+
+ SignalSpy {
+ id: windowPropertyChangedSpy
+ target: WindowManager
+ signalName: "windowPropertyChanged"
+ }
+
+ function test_basic_data() {
+ return [ { tag: "app1" },
+ { tag: "app2" } ];
+ }
+
+ function test_basic(data) {
+ wait(1200); // wait for quicklaunch
+
+ var app = ApplicationManager.application(data.tag);
+ windowPropertyChangedSpy.clear();
+
+ app.start();
+ while (app.runState !== ApplicationObject.Running)
+ runStateChangedSpy.wait(3000);
+
+ if (data.tag === "app2") {
+ windowPropertyChangedSpy.wait(2000);
+ compare(windowPropertyChangedSpy.count, 1);
+ compare(windowPropertyChangedSpy.signalArguments[0][0].windowProperty("meaning"), 42);
+ }
+
+ app.stop();
+ while (app.runState !== ApplicationObject.NotRunning)
+ runStateChangedSpy.wait(3000);
+ }
+}
diff --git a/tests/qml/simple/am-config.yaml b/tests/qml/simple/am-config.yaml
index 46309470..2a515905 100644
--- a/tests/qml/simple/am-config.yaml
+++ b/tests/qml/simple/am-config.yaml
@@ -3,16 +3,6 @@ formatType: am-configuration
---
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/apps"
- installedAppsManifestDir: "/tmp/am-simple-test/manifests"
- appImageMountDir: "/tmp/am-simple-test/image-mounts"
- database: "/tmp/am-simple-test/apps.db"
-
-installationLocations:
-- id: "internal-0"
- installationPath: "/tmp/am/apps"
- documentPath: "/tmp/am/docs"
- mountPoint: "/tmp"
- isDefault: true
ui:
fullscreen: no
diff --git a/tests/qml/simple/apps/tld.test.simple1/app1.qml b/tests/qml/simple/apps/tld.test.simple1/app1.qml
index fb38c958..f0402209 100644
--- a/tests/qml/simple/apps/tld.test.simple1/app1.qml
+++ b/tests/qml/simple/apps/tld.test.simple1/app1.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/simple/apps/tld.test.simple1/info-alias.yaml b/tests/qml/simple/apps/tld.test.simple1/info-alias.yaml
deleted file mode 100644
index ec600862..00000000
--- a/tests/qml/simple/apps/tld.test.simple1/info-alias.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-formatVersion: 1
-formatType: am-application-alias
----
-aliasId: 'tld.test.simple1@alias'
-icon: 'icon2.png'
-name:
- en: 'Simple1 Alias'
-
-documentUrl: "x-test:alias"
diff --git a/tests/qml/simple/apps/tld.test.simple2/app.qml b/tests/qml/simple/apps/tld.test.simple2/app.qml
index 2a09855d..b0506e1f 100644
--- a/tests/qml/simple/apps/tld.test.simple2/app.qml
+++ b/tests/qml/simple/apps/tld.test.simple2/app.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/simple/simple.pro b/tests/qml/simple/simple.pro
index 375f62c5..72dbea95 100644
--- a/tests/qml/simple/simple.pro
+++ b/tests/qml/simple/simple.pro
@@ -1,4 +1,5 @@
AM_CONFIG = am-config.yaml
TEST_FILES = tst_applicationmanager.qml
+TEST_APPS = tld.test.simple1 tld.test.simple2
load(am-qml-testcase)
diff --git a/tests/qml/simple/tst_applicationmanager.qml b/tests/qml/simple/tst_applicationmanager.qml
index d945c477..8b62425f 100644
--- a/tests/qml/simple/tst_applicationmanager.qml
+++ b/tests/qml/simple/tst_applicationmanager.qml
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -51,10 +52,10 @@ TestCase {
name: "ApplicationManager"
property var simpleApplication
- property var applicationAlias
property var capsApplication
// Either appman is build in single-process mode or it was started with --force-single-process
- property bool singleProcess : Qt.application.arguments.indexOf("--force-single-process") !== -1 || buildConfig[0].CONFIG.indexOf("multi-process") === -1
+ property bool singleProcess : Qt.application.arguments.indexOf("--force-single-process") !== -1
+ || buildConfig[0].CONFIG.indexOf("multi-process") === -1
property QtObject windowHandler: QtObject {
function windowAddedHandler(window) {
console.info("window " + window + " added");
@@ -84,10 +85,9 @@ TestCase {
WindowManager.windowAdded.connect(windowHandler.windowAddedHandler)
WindowManager.windowContentStateChanged.connect(windowHandler.windowContentStateChangedHandler)
- compare(ApplicationManager.count, 3)
+ compare(ApplicationManager.count, 2)
simpleApplication = ApplicationManager.application(0);
- applicationAlias = ApplicationManager.application(1);
- capsApplication = ApplicationManager.application(2);
+ capsApplication = ApplicationManager.application(1);
}
function test_properties() {
@@ -152,23 +152,10 @@ TestCase {
compare(simpleApplication.applicationProperties.pri1, undefined)
}
- function test_applicationAlias() {
- // Test that the alias has the same info, be indentified as an alias and points to the original app
- compare(applicationAlias.id, "tld.test.simple1@alias")
- compare(applicationAlias.alias, true)
- compare(applicationAlias.nonAliased, simpleApplication)
- //TODO this should be a Url instead, as this is what's used in QML usually
- compare(applicationAlias.icon.toString(), Qt.resolvedUrl("apps/tld.test.simple1/icon2.png"))
- compare(applicationAlias.documentUrl, "x-test:alias")
- compare(applicationAlias.runtimeName, simpleApplication.runtimeName)
- compare(applicationAlias.capabilities, simpleApplication.capabilities)
- compare(applicationAlias.supportedMimeTypes, simpleApplication.supportedMimeTypes)
- }
-
function test_indexOfApplication() {
// Test index of
compare(ApplicationManager.indexOfApplication(simpleApplication.id), 0)
- compare(ApplicationManager.indexOfApplication(applicationAlias.id), 1)
+ compare(ApplicationManager.indexOfApplication(capsApplication.id), 1)
compare(ApplicationManager.indexOfApplication("error"), -1)
}
@@ -177,7 +164,7 @@ TestCase {
var apps = ApplicationManager.applicationIds()
compare(apps.length, ApplicationManager.count)
compare(ApplicationManager.applicationIds()[0], simpleApplication.id)
- compare(ApplicationManager.applicationIds()[1], applicationAlias.id)
+ compare(ApplicationManager.applicationIds()[1], capsApplication.id)
}
function test_capabilities() {
@@ -214,18 +201,15 @@ TestCase {
}
function test_applicationModel() {
- compare(appModel.count, 3);
+ compare(appModel.count, 2);
compare(appModel.indexOfApplication(capsApplication.id), 0);
- compare(appModel.indexOfApplication(applicationAlias.id), 1);
- compare(appModel.indexOfApplication(simpleApplication.id), 2);
+ compare(appModel.indexOfApplication(simpleApplication.id), 1);
compare(appModel.mapToSource(0), ApplicationManager.indexOfApplication(capsApplication.id));
- compare(appModel.mapFromSource(ApplicationManager.indexOfApplication(simpleApplication.id)), 2);
+ compare(appModel.mapFromSource(ApplicationManager.indexOfApplication(simpleApplication.id)), 1);
appModel.sortFunction = undefined;
compare(appModel.indexOfApplication(simpleApplication.id),
ApplicationManager.indexOfApplication(simpleApplication.id));
- compare(appModel.indexOfApplication(applicationAlias.id),
- ApplicationManager.indexOfApplication(applicationAlias.id));
compare(appModel.indexOfApplication(capsApplication.id),
ApplicationManager.indexOfApplication(capsApplication.id));
@@ -235,7 +219,6 @@ TestCase {
compare(appModelCountSpy.count, 1);
compare(appModel.count, 1);
compare(appModel.indexOfApplication(capsApplication.id), 0);
- compare(appModel.indexOfApplication(applicationAlias.id), -1);
compare(appModel.indexOfApplication(simpleApplication.id), -1);
listView.model = appModel;
@@ -243,21 +226,11 @@ TestCase {
compare(listView.currentItem.modelData.name, "Caps");
listView.model = ApplicationManager;
- var criteria = false;
- appModel.filterFunction = function(app) { return app.alias === criteria; };
- appModelCountSpy.wait(1000);
- compare(appModelCountSpy.count, 2);
- compare(appModel.count, 2);
- compare(appModel.indexOfApplication(applicationAlias.id), -1);
- criteria = true;
- appModel.invalidate();
- compare(appModel.count, 1);
-
appModel.filterFunction = function() {};
compare(appModel.count, 0);
appModel.filterFunction = undefined;
- compare(appModel.count, 3);
+ compare(appModel.count, 2);
}
function test_get_data() {
@@ -318,11 +291,16 @@ TestCase {
function test_startAndStopApplication_data() {
return [
- {tag: "StartStop", appId: "tld.test.simple1", index: 0, forceKill: false, exitCode: 0, exitStatus: Am.NormalExit },
- {tag: "StartStopAlias", appId: "tld.test.simple1@alias", index: 0, forceKill: false, exitCode: 0, exitStatus: Am.NormalExit },
- {tag: "Debug", appId: "tld.test.simple1", index: 0, forceKill: false, exitCode: 0, exitStatus: Am.NormalExit },
- {tag: "ForceKill", appId: "tld.test.simple2", index: 2, forceKill: true, exitCode: Qt.platform.os !== 'windows' ? 9 : 0, exitStatus: Qt.platform.os !== 'windows' ? Am.ForcedExit : Am.CrashExit },
- {tag: "AutoTerminate", appId: "tld.test.simple2", index: 2, forceKill: false, exitCode: Qt.platform.os !== 'windows' ? 15 : 0, exitStatus: Qt.platform.os !== 'windows' ? Am.ForcedExit : Am.CrashExit }
+ {tag: "StartStop", appId: "tld.test.simple1", index: 0, forceKill: false,
+ exitCode: 0, exitStatus: Am.NormalExit },
+ {tag: "Debug", appId: "tld.test.simple1", index: 0, forceKill: false,
+ exitCode: 0, exitStatus: Am.NormalExit },
+ {tag: "ForceKill", appId: "tld.test.simple2", index: 1, forceKill: true,
+ exitCode: Qt.platform.os !== 'windows' ? 9 : 0,
+ exitStatus: Qt.platform.os !== 'windows' ? Am.ForcedExit : Am.CrashExit },
+ {tag: "AutoTerminate", appId: "tld.test.simple2", index: 1, forceKill: false,
+ exitCode: Qt.platform.os !== 'windows' ? 15 : 0,
+ exitStatus: Qt.platform.os !== 'windows' ? Am.ForcedExit : Am.CrashExit }
];
}
@@ -369,7 +347,9 @@ TestCase {
function test_startAndStopAllApplications_data() {
return [
- {tag: "StopAllApplications", appId1: "tld.test.simple1", index1: 0, appId2: "tld.test.simple2", index2: 2, forceKill: false, exitCode: 0, exitStatus: Am.NormalExit }
+ {tag: "StopAllApplications", appId1: "tld.test.simple1", index1: 0,
+ appId2: "tld.test.simple2", index2: 1, forceKill: false, exitCode: 0,
+ exitStatus: Am.NormalExit }
];
}
@@ -408,12 +388,12 @@ TestCase {
ApplicationManager.stopAllApplications(data.forceKill);
- while (runStateChangedSpy.count < 6)
+ while (runStateChangedSpy.count < 4)
runStateChangedSpy.wait(10000);
var args = runStateChangedSpy.signalArguments
- for (var i = 0; i < 6; ++i) {
+ for (var i = 0; i < 4; ++i) {
var id = args[i][0]
var state = args[i][1]
@@ -460,7 +440,6 @@ TestCase {
function test_openUrl_data() {
return [
{tag: "customMimeType", url: "x-test://12345", expectedApp: simpleApplication.id },
- {tag: "openAlias", url: "x-test:alias", expectedApp: applicationAlias.id },
{tag: "text/plain", url: "file://text-file.txt", expectedApp: simpleApplication.id }
];
}
diff --git a/tests/qml/windowitem/am-config.yaml b/tests/qml/windowitem/am-config.yaml
index 34a4c56a..aa82540b 100644
--- a/tests/qml/windowitem/am-config.yaml
+++ b/tests/qml/windowitem/am-config.yaml
@@ -3,16 +3,8 @@ formatType: am-configuration
---
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/apps"
- installedAppsManifestDir: "/tmp/am/manifests"
- appImageMountDir: "/tmp/am/image-mounts"
- database: "/tmp/am/apps.db"
-
-installationLocations:
-- id: "internal-0"
- installationPath: "/tmp/am/apps"
- documentPath: "/tmp/am/docs"
- mountPoint: "/tmp"
- isDefault: true
+ installationDir: "/tmp/am/apps"
+ documentDir: "/tmp/am/docs"
# Workaround for a crash in the mesa software renderer (llvmpipe)
runtimes:
diff --git a/tests/qml/windowitem/apps/test.windowitem.app/main.qml b/tests/qml/windowitem/apps/test.windowitem.app/main.qml
index 8f64f980..ee12db6f 100644
--- a/tests/qml/windowitem/apps/test.windowitem.app/main.qml
+++ b/tests/qml/windowitem/apps/test.windowitem.app/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowitem/apps/test.windowitem.multiwin/main.qml b/tests/qml/windowitem/apps/test.windowitem.multiwin/main.qml
index f12323be..7d1b0600 100644
--- a/tests/qml/windowitem/apps/test.windowitem.multiwin/main.qml
+++ b/tests/qml/windowitem/apps/test.windowitem.multiwin/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowitem/tst_windowitem.qml b/tests/qml/windowitem/tst_windowitem.qml
index ea835267..15cd4f5b 100644
--- a/tests/qml/windowitem/tst_windowitem.qml
+++ b/tests/qml/windowitem/tst_windowitem.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowitem/windowitem.pro b/tests/qml/windowitem/windowitem.pro
index d2755653..fcc1b1f6 100644
--- a/tests/qml/windowitem/windowitem.pro
+++ b/tests/qml/windowitem/windowitem.pro
@@ -1,4 +1,5 @@
AM_CONFIG = am-config.yaml
TEST_FILES = tst_windowitem.qml
+TEST_APPS = test.windowitem.app test.windowitem.multiwin
load(am-qml-testcase)
diff --git a/tests/qml/windowitem2/am-config.yaml b/tests/qml/windowitem2/am-config.yaml
index ee4edd72..5333dae3 100644
--- a/tests/qml/windowitem2/am-config.yaml
+++ b/tests/qml/windowitem2/am-config.yaml
@@ -3,16 +3,6 @@ formatType: am-configuration
---
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/apps"
- installedAppsManifestDir: "/tmp/am-windowitem2/manifests"
- appImageMountDir: "/tmp/am-windowitem2/image-mounts"
- database: "/tmp/am-windowitem2/apps.db"
-
-installationLocations:
-- id: "internal-0"
- installationPath: "/tmp/am-windowitem2/apps"
- documentPath: "/tmp/am-windowitem2/docs"
- mountPoint: "/tmp"
- isDefault: true
# Workaround for a crash in the mesa software renderer (llvmpipe)
runtimes:
diff --git a/tests/qml/windowitem2/apps/test.windowitem2.app/main.qml b/tests/qml/windowitem2/apps/test.windowitem2.app/main.qml
index 84dfdb3e..ab891bb8 100644
--- a/tests/qml/windowitem2/apps/test.windowitem2.app/main.qml
+++ b/tests/qml/windowitem2/apps/test.windowitem2.app/main.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowitem2/tst_windowitem2.qml b/tests/qml/windowitem2/tst_windowitem2.qml
index 5c411805..98d4ef30 100644
--- a/tests/qml/windowitem2/tst_windowitem2.qml
+++ b/tests/qml/windowitem2/tst_windowitem2.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowitem2/windowitem2.pro b/tests/qml/windowitem2/windowitem2.pro
index fe1ab58a..022ea053 100644
--- a/tests/qml/windowitem2/windowitem2.pro
+++ b/tests/qml/windowitem2/windowitem2.pro
@@ -1,4 +1,5 @@
AM_CONFIG = am-config.yaml
TEST_FILES = tst_windowitem2.qml
+TEST_APPS = test.windowitem2.app
load(am-qml-testcase)
diff --git a/tests/qml/windowmanager/IviApplicationExtension.qml b/tests/qml/windowmanager/IviApplicationExtension.qml
index f85f147d..3e4a9700 100644
--- a/tests/qml/windowmanager/IviApplicationExtension.qml
+++ b/tests/qml/windowmanager/IviApplicationExtension.qml
@@ -3,7 +3,7 @@
** Copyright (C) 2019 Luxoft Sweden AB
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowmanager/am-config.yaml b/tests/qml/windowmanager/am-config.yaml
deleted file mode 100644
index d5d4813b..00000000
--- a/tests/qml/windowmanager/am-config.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-formatVersion: 1
-formatType: am-configuration
----
-applications:
- installedAppsManifestDir: "/tmp/am/manifests"
- appImageMountDir: "/tmp/am/image-mounts"
- database: "/tmp/am/apps.db"
-
-installationLocations:
-- id: "internal-0"
- installationPath: "/tmp/am/apps"
- documentPath: "/tmp/am/docs"
- mountPoint: "/tmp"
- isDefault: true
diff --git a/tests/qml/windowmanager/tst_windowmanager.qml b/tests/qml/windowmanager/tst_windowmanager.qml
index c2a556cd..11cb9265 100644
--- a/tests/qml/windowmanager/tst_windowmanager.qml
+++ b/tests/qml/windowmanager/tst_windowmanager.qml
@@ -3,7 +3,7 @@
** Copyright (C) 2019 Luxoft Sweden AB
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowmanager/windowmanager.pro b/tests/qml/windowmanager/windowmanager.pro
index d9b687eb..21cd8a91 100644
--- a/tests/qml/windowmanager/windowmanager.pro
+++ b/tests/qml/windowmanager/windowmanager.pro
@@ -1,4 +1,5 @@
-AM_CONFIG = am-config.yaml
TEST_FILES = tst_windowmanager.qml
+OTHER_FILES += IviApplicationExtension.qml
+
load(am-qml-testcase)
diff --git a/tests/qml/windowmapping/am-config.yaml b/tests/qml/windowmapping/am-config.yaml
index 34a4c56a..5333dae3 100644
--- a/tests/qml/windowmapping/am-config.yaml
+++ b/tests/qml/windowmapping/am-config.yaml
@@ -3,16 +3,6 @@ formatType: am-configuration
---
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/apps"
- installedAppsManifestDir: "/tmp/am/manifests"
- appImageMountDir: "/tmp/am/image-mounts"
- database: "/tmp/am/apps.db"
-
-installationLocations:
-- id: "internal-0"
- installationPath: "/tmp/am/apps"
- documentPath: "/tmp/am/docs"
- mountPoint: "/tmp"
- isDefault: true
# Workaround for a crash in the mesa software renderer (llvmpipe)
runtimes:
diff --git a/tests/qml/windowmapping/apps/test.winmap.amwin/amwin.qml b/tests/qml/windowmapping/apps/test.winmap.amwin/amwin.qml
index 470d6dc0..a93f30d4 100644
--- a/tests/qml/windowmapping/apps/test.winmap.amwin/amwin.qml
+++ b/tests/qml/windowmapping/apps/test.winmap.amwin/amwin.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml b/tests/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml
index 8c104a05..b10709d3 100644
--- a/tests/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml
+++ b/tests/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml b/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml
index af0001d6..8ba50e22 100644
--- a/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml
+++ b/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml b/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml
index 569fef1a..0a65690e 100644
--- a/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml
+++ b/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowmapping/apps/test.winmap.ping/ping.qml b/tests/qml/windowmapping/apps/test.winmap.ping/ping.qml
index 59267c04..6fa9ba23 100644
--- a/tests/qml/windowmapping/apps/test.winmap.ping/ping.qml
+++ b/tests/qml/windowmapping/apps/test.winmap.ping/ping.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml b/tests/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml
index c1c8ba3d..325c04de 100644
--- a/tests/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml
+++ b/tests/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml b/tests/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml
index 718b787d..fe6cdee3 100644
--- a/tests/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml
+++ b/tests/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowmapping/apps/test.winmap.window/window.qml b/tests/qml/windowmapping/apps/test.winmap.window/window.qml
index c10a57b0..a0832d15 100644
--- a/tests/qml/windowmapping/apps/test.winmap.window/window.qml
+++ b/tests/qml/windowmapping/apps/test.winmap.window/window.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowmapping/tst_windowmapping.qml b/tests/qml/windowmapping/tst_windowmapping.qml
index 00a6e582..dda075e5 100644
--- a/tests/qml/windowmapping/tst_windowmapping.qml
+++ b/tests/qml/windowmapping/tst_windowmapping.qml
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
diff --git a/tests/qml/windowmapping/windowmapping.pro b/tests/qml/windowmapping/windowmapping.pro
index 59fa55b0..e29aba28 100644
--- a/tests/qml/windowmapping/windowmapping.pro
+++ b/tests/qml/windowmapping/windowmapping.pro
@@ -1,4 +1,12 @@
AM_CONFIG = am-config.yaml
TEST_FILES = tst_windowmapping.qml
+TEST_APPS = \
+ test.winmap.amwin \
+ test.winmap.amwin2 \
+ test.winmap.loader \
+ test.winmap.ping \
+ test.winmap.qtobject \
+ test.winmap.rectangle \
+ test.winmap.window \
load(am-qml-testcase)
diff --git a/tests/runtime/tst_runtime.cpp b/tests/runtime/tst_runtime.cpp
index 615417e4..d64014e2 100644
--- a/tests/runtime/tst_runtime.cpp
+++ b/tests/runtime/tst_runtime.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
@@ -31,7 +32,7 @@
#include <QQmlEngine>
#include "application.h"
-#include "yamlapplicationscanner.h"
+#include "package.h"
#include "abstractruntime.h"
#include "runtimefactory.h"
#include "exception.h"
@@ -62,19 +63,19 @@ public:
void setSlowAnimations(bool) override {}
- qint64 applicationProcessId() const
+ qint64 applicationProcessId() const override
{
return m_state == Am::Running ? 1 : 0;
}
public slots:
- bool start()
+ bool start() override
{
m_state = Am::Running;
return true;
}
- void stop(bool forceKill)
+ void stop(bool forceKill) override
{
Q_UNUSED(forceKill);
m_state = Am::NotRunning;
@@ -137,7 +138,10 @@ void tst_Runtime::factory()
Application *a = nullptr;
try {
- a = new Application(YamlApplicationScanner().scan(temp.fileName()));
+ PackageInfo *pi = PackageInfo::fromManifest(temp.fileName());
+ QVERIFY(pi);
+ Package *p = new Package(pi);
+ a = new Application(pi->applications().first(), p);
} catch (const Exception &e) {
QVERIFY2(false, qPrintable(e.errorString()));
}
diff --git a/tests/signature/create-test-data.sh b/tests/signature/create-test-data.sh
index 943ade2a..d599d18d 100755
--- a/tests/signature/create-test-data.sh
+++ b/tests/signature/create-test-data.sh
@@ -5,7 +5,7 @@
## Copyright (C) 2018 Pelagicore AG
## Contact: https://www.qt.io/licensing/
##
-## This file is part of the Luxoft Application Manager.
+## This file is part of the Qt Application Manager.
##
## $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
## Commercial License Usage
diff --git a/tests/signature/signature.pro b/tests/signature/signature.pro
index 77ff71f1..43bb3d47 100644
--- a/tests/signature/signature.pro
+++ b/tests/signature/signature.pro
@@ -6,4 +6,6 @@ QT *= appman_common-private appman_crypto-private
SOURCES += tst_signature.cpp
+OTHER_FILES += create-test-data.sh
+
RESOURCES += tst_signature.qrc
diff --git a/tests/signature/tst_signature.cpp b/tests/signature/tst_signature.cpp
index c8713457..9f48590a 100644
--- a/tests/signature/tst_signature.cpp
+++ b/tests/signature/tst_signature.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/tests/sudo/sudo.pro b/tests/sudo/sudo.pro
index 9745e2fc..95be319b 100644
--- a/tests/sudo/sudo.pro
+++ b/tests/sudo/sudo.pro
@@ -6,6 +6,6 @@ include($$PWD/../tests.pri)
QT *= \
appman_common-private \
- appman_installer-private \
+ appman_manager-private \
SOURCES += tst_sudo.cpp
diff --git a/tests/sudo/tst_sudo.cpp b/tests/sudo/tst_sudo.cpp
index 6ce7685e..0fb2b2ad 100644
--- a/tests/sudo/tst_sudo.cpp
+++ b/tests/sudo/tst_sudo.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/tests/systemreader/tst_systemreader.cpp b/tests/systemreader/tst_systemreader.cpp
index 48c75c23..d69478ee 100644
--- a/tests/systemreader/tst_systemreader.cpp
+++ b/tests/systemreader/tst_systemreader.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/tests/tests.pro b/tests/tests.pro
index 0b9409df..35e95a36 100644
--- a/tests/tests.pro
+++ b/tests/tests.pro
@@ -1,6 +1,7 @@
TEMPLATE = subdirs
SUBDIRS = \
+ manual \
application \
applicationinfo \
main \
@@ -8,6 +9,7 @@ SUBDIRS = \
cryptography \
signature \
utilities \
+ yaml \
installationreport \
packagecreator \
packageextractor \
@@ -25,6 +27,7 @@ OTHER_FILES += \
tests.pri \
data/create-test-packages.sh \
data/certificates/create-test-certificates.sh \
+ data/utilities.sh \
# sadly, the appman-packager is too complex to build as a host tool
!cross_compile {
diff --git a/tests/utilities/tst_utilities.cpp b/tests/utilities/tst_utilities.cpp
index 47689907..5b4ed8e4 100644
--- a/tests/utilities/tst_utilities.cpp
+++ b/tests/utilities/tst_utilities.cpp
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/tests/yaml/data/cache1.yaml b/tests/yaml/data/cache1.yaml
new file mode 100644
index 00000000..b3fcddb9
--- /dev/null
+++ b/tests/yaml/data/cache1.yaml
@@ -0,0 +1,13 @@
+name: cache1
+file: ${FILE}
+
+## content for a merge test
+#bool: true
+#list: [ 1, 2 ]
+#map:
+# key1: value1
+# key2: value2
+# key3:
+# key31: value31
+# key32: value32
+# key4: 4
diff --git a/tests/yaml/data/cache2.yaml b/tests/yaml/data/cache2.yaml
new file mode 100644
index 00000000..8ce7bae3
--- /dev/null
+++ b/tests/yaml/data/cache2.yaml
@@ -0,0 +1,14 @@
+name: cache2
+file: ${FILE}
+
+## content for a merge test
+#bool: false
+#list: [ 3, 4, 5 ]
+#map:
+# key1: value1
+# key2: not-value2
+# key3:
+# key31: [ 5, 6 ]
+# key32: not-value32
+# key33: true
+# key5: 5
diff --git a/tests/yaml/data/test.yaml b/tests/yaml/data/test.yaml
new file mode 100644
index 00000000..b16e3d39
--- /dev/null
+++ b/tests/yaml/data/test.yaml
@@ -0,0 +1,45 @@
+formatVersion: 42
+formatType: testfile
+---
+dec: 10
+hex: 0x10
+oct: 010
+bin: 0b10
+float1: 10.10
+float2: 0.10
+float3: .10
+number-separators: 1_234_567
+bool-true: true
+bool-yes: yes
+bool-false: false
+bool-no: no
+null-literal: null
+null-tilde: ~
+string-unquoted: unquoted
+string-singlequoted: 'singlequoted'
+string-doublequoted: "doublequoted"
+list-int:
+- 1
+- 2
+- 3
+list-mixed:
+- 1
+- two
+- [yes, ~]
+map1:
+ a: 1
+ b: two
+ c: [ 1, 2, 3]
+
+extended:
+ ext-string: 'ext string'
+
+stringlist-string: string
+stringlist-list1: [ string ]
+stringlist-list2: [ string1, string2 ]
+
+list-of-maps:
+- index: 1
+ name: '1'
+- index: 2
+ name: '2'
diff --git a/tests/yaml/tst_yaml.cpp b/tests/yaml/tst_yaml.cpp
new file mode 100644
index 00000000..1b53e533
--- /dev/null
+++ b/tests/yaml/tst_yaml.cpp
@@ -0,0 +1,340 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 <QtCore>
+#include <QtTest>
+
+#include "qtyaml.h"
+#include "configcache.h"
+#include "exception.h"
+#include "global.h"
+
+QT_USE_NAMESPACE_AM
+
+class tst_Yaml : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_Yaml();
+
+private slots:
+ void parser();
+ void documentParser();
+ void cache();
+ void mergedCache();
+};
+
+
+tst_Yaml::tst_Yaml()
+{ }
+
+void tst_Yaml::parser()
+{
+ static const QVariant vnull = QVariant::fromValue(nullptr);
+
+ QVector<QPair<const char *, QVariant>> tests = {
+ { "dec", QVariant::fromValue<int>(10) },
+ { "hex", QVariant::fromValue<int>(16) },
+ { "bin", QVariant::fromValue<int>(2) },
+ { "oct", QVariant::fromValue<int>(8) },
+ { "float1", QVariant::fromValue<double>(10.1) },
+ { "float2", QVariant::fromValue<double>(.1) },
+ { "float3", QVariant::fromValue<double>(.1) },
+ { "number-separators", QVariant::fromValue<int>(1234567) },
+ { "bool-true", true },
+ { "bool-yes", true },
+ { "bool-false", false },
+ { "bool-no", false },
+ { "null-literal", vnull },
+ { "null-tilde", vnull },
+ { "string-unquoted", QVariant::fromValue<QString>("unquoted") },
+ { "string-singlequoted", QVariant::fromValue<QString>("singlequoted") },
+ { "string-doublequoted", QVariant::fromValue<QString>("doublequoted") },
+ { "list-int", QVariantList { 1, 2, 3 } },
+ { "list-mixed", QVariantList { 1, "two", QVariantList { true, vnull } } },
+ { "map1", QVariantMap { { "a", 1 }, { "b", "two" }, { "c", QVariantList { 1, 2, 3 } } } }
+ };
+
+ try {
+ QFile f(":/data/test.yaml");
+ QVERIFY2(f.open(QFile::ReadOnly), qPrintable(f.errorString()));
+ QByteArray ba = f.readAll();
+ QVERIFY(!ba.isEmpty());
+ YamlParser p(ba);
+ auto header = p.parseHeader();
+
+ QCOMPARE(header.first, "testfile");
+ QCOMPARE(header.second, 42);
+
+ QVERIFY(p.nextDocument());
+
+ YamlParser::Fields fields;
+ for (const auto &pair : tests) {
+ YamlParser::FieldType type = YamlParser::Scalar;
+ if (pair.second.type() == QVariant::List)
+ type = YamlParser::List;
+ else if (pair.second.type() == QVariant::Map)
+ type = YamlParser::Map;
+ QVariant value = pair.second;
+
+ fields.emplace_back(pair.first, true, type, [type, value](YamlParser *p) {
+ switch (type) {
+ case YamlParser::Scalar: {
+ QVERIFY(p->isScalar());
+ QVariant v = p->parseScalar();
+ QCOMPARE(int(v.type()), int(value.type()));
+ QVERIFY(v == value);
+ break;
+ }
+ case YamlParser::List: {
+ QVERIFY(p->isList());
+ QVariantList vl = p->parseList();
+ QVERIFY(vl == value.toList());
+ break;
+ }
+ case YamlParser::Map: {
+ QVERIFY(p->isMap());
+ QVariantMap vm = p->parseMap();
+ QVERIFY(vm == value.toMap());
+ break;
+ }
+ }
+ });
+ }
+ fields.emplace_back("extended", true, YamlParser::Map, [](YamlParser *p) {
+ YamlParser::Fields extFields = {
+ { "ext-string", true, YamlParser::Scalar, [](YamlParser *p) {
+ QVERIFY(p->isScalar());
+ QVariant v = p->parseScalar();
+ QCOMPARE(v.type(), QVariant::String);
+ QCOMPARE(v.toString(), "ext string");
+ } }
+ };
+ p->parseFields(extFields);
+ });
+
+ fields.emplace_back("stringlist-string", true, YamlParser::Scalar | YamlParser::List, [](YamlParser *p) {
+ QCOMPARE(p->parseStringOrStringList(), QStringList { "string" });
+ });
+ fields.emplace_back("stringlist-list1", true, YamlParser::Scalar | YamlParser::List, [](YamlParser *p) {
+ QCOMPARE(p->parseStringOrStringList(), QStringList { "string" });
+ });
+ fields.emplace_back("stringlist-list2", true, YamlParser::Scalar | YamlParser::List, [](YamlParser *p) {
+ QCOMPARE(p->parseStringOrStringList(), QStringList({ "string1", "string2" }));
+ });
+
+ fields.emplace_back("list-of-maps", true, YamlParser::List, [](YamlParser *p) {
+ int index = 0;
+ p->parseList([&index](YamlParser *p) {
+ ++index;
+ YamlParser::Fields lomFields = {
+ { "index", true, YamlParser::Scalar, [&index](YamlParser *p) {
+ QCOMPARE(p->parseScalar().toInt(), index);
+ } },
+ { "name", true, YamlParser::Scalar, [&index](YamlParser *p) {
+ QCOMPARE(p->parseScalar().toString(), QString::number(index));
+ } }
+ };
+ p->parseFields(lomFields);
+ });
+ QCOMPARE(index, 2);
+ });
+
+ p.parseFields(fields);
+
+ QVERIFY(!p.nextDocument());
+
+ } catch (const Exception &e) {
+ QVERIFY2(false, e.what());
+ }
+}
+
+void tst_Yaml::documentParser()
+{
+ static const QVariant vnull = QVariant::fromValue(nullptr);
+
+ try {
+ QFile f(":/data/test.yaml");
+ QVERIFY2(f.open(QFile::ReadOnly), qPrintable(f.errorString()));
+ QByteArray ba = f.readAll();
+ QVERIFY(!ba.isEmpty());
+ QVector<QVariant> docs = YamlParser::parseAllDocuments(ba);
+ QCOMPARE(docs.size(), 2);
+ QCOMPARE(docs.at(0).toMap().size(), 2);
+
+ QVariantMap header = {
+ { "formatVersion", 42 }, { "formatType", "testfile" }
+ };
+
+ QVariantMap main = {
+ { "dec", 10 },
+ { "hex", 16 },
+ { "bin", 2 },
+ { "oct", 8 },
+ { "float1", 10.1 },
+ { "float2", .1 },
+ { "float3", .1 },
+ { "number-separators", 1234567 },
+ { "bool-true", true },
+ { "bool-yes", true },
+ { "bool-false", false },
+ { "bool-no", false },
+ { "null-literal", vnull },
+ { "null-tilde", vnull },
+ { "string-unquoted", "unquoted" },
+ { "string-singlequoted", "singlequoted" },
+ { "string-doublequoted", "doublequoted" },
+ { "list-int", QVariantList { 1, 2, 3 } },
+ { "list-mixed", QVariantList { 1, qSL("two"), QVariantList { true, vnull } } },
+ { "map1", QVariantMap { { "a", 1 }, { "b", "two" }, { "c", QVariantList { 1, 2, 3 } } } },
+
+
+ { "extended", QVariantMap { { "ext-string", "ext string" } } },
+
+ { "stringlist-string", "string" },
+ { "stringlist-list1", QVariantList { "string" } },
+ { "stringlist-list2", QVariantList { "string1", "string2" } },
+
+ { "list-of-maps", QVariantList { QVariantMap { { "index", 1 }, { "name", "1" } },
+ QVariantMap { { "index", 2 }, { "name", "2" } } } }
+ };
+
+ QCOMPARE(header, docs.at(0).toMap());
+ QCOMPARE(main, docs.at(1).toMap());
+
+ } catch (const Exception &e) {
+ QVERIFY2(false, e.what());
+ }
+}
+struct CacheTest
+{
+ QString name;
+ QString file;
+};
+
+// GCC < 7 bug, currently still in RHEL7, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480
+// this should simply be:
+// template<> class QT_PREPEND_NAMESPACE_AM(ConfigCacheAdaptor<CacheTest>)
+
+QT_BEGIN_NAMESPACE_AM
+template<> class ConfigCacheAdaptor<CacheTest>
+{
+public:
+ CacheTest *loadFromSource(QIODevice *source, const QString &fileName)
+ {
+ QScopedPointer<CacheTest> ct(new CacheTest);
+ YamlParser p(source->readAll(), fileName);
+ p.nextDocument();
+ p.parseFields({ { "name", true, YamlParser::Scalar, [&ct](YamlParser *p) {
+ ct->name = p->parseScalar().toString(); } },
+ { "file", true, YamlParser::Scalar, [&ct](YamlParser *p) {
+ ct->file = p->parseScalar().toString(); } }
+ });
+ return ct.take();
+ }
+ CacheTest *loadFromCache(QDataStream &ds)
+ {
+ CacheTest *ct = new CacheTest;
+ ds >> ct->name >> ct->file;
+ return ct;
+ }
+ void saveToCache(QDataStream &ds, const CacheTest *ct)
+ {
+ ds << ct->name << ct->file;
+ }
+
+ void merge(CacheTest *ct1, const CacheTest *ct2)
+ {
+ ct1->name = ct2->name;
+ ct1->file = ct1->file + qSL(",") + ct2->file;
+ }
+ void preProcessSourceContent(QByteArray &sourceContent, const QString &fileName)
+ {
+ sourceContent.replace("${FILE}", fileName.toUtf8());
+ }
+ QStringList *warnings;
+};
+QT_END_NAMESPACE_AM
+
+void tst_Yaml::cache()
+{
+ QStringList files = { ":/data/cache1.yaml", ":/data/cache2.yaml" };
+ QStringList warnings;
+
+ for (int step = 0; step < 2; ++step) {
+ try {
+ ConfigCache<CacheTest> cache(files, "cache-test", step == 0 ? AbstractConfigCache::ClearCache
+ : AbstractConfigCache::None);
+ cache.parse(&warnings);
+ QVERIFY2(warnings.isEmpty(), qPrintable(warnings.join(qSL("\n"))));
+ CacheTest *ct1 = cache.takeResult(0);
+ QVERIFY(ct1);
+ QCOMPARE(ct1->name, "cache1");
+ QCOMPARE(ct1->file, ":/data/cache1.yaml");
+ CacheTest *ct2 = cache.takeResult(1);
+ QVERIFY(ct2);
+ QCOMPARE(ct2->name, "cache2");
+ QCOMPARE(ct2->file, ":/data/cache2.yaml");
+ } catch (const Exception &e) {
+ QVERIFY2(false, e.what());
+ }
+ }
+}
+
+void tst_Yaml::mergedCache()
+{
+ QStringList files = { ":/data/cache1.yaml", ":/data/cache2.yaml" };
+ QStringList warnings;
+
+ for (int step = 0; step < 4; ++step) {
+ AbstractConfigCache::Options options = AbstractConfigCache::MergedResult;
+ if (step % 2 == 0)
+ options |= AbstractConfigCache::ClearCache;
+ if (step == 2)
+ std::reverse(files.begin(), files.end());
+
+ try {
+ ConfigCache<CacheTest> cache(files, "cache-test", options);
+ cache.parse(&warnings);
+ QVERIFY2(warnings.isEmpty(), qPrintable(warnings.join(qSL("\n"))));
+ CacheTest *ct = cache.takeMergedResult();
+ QVERIFY(ct);
+ QCOMPARE(ct->name, QFileInfo(files.last()).baseName());
+ QCOMPARE(ct->file, files.join(qSL(",")));
+ } catch (const Exception &e) {
+ QVERIFY2(false, e.what());
+ }
+ }
+}
+
+QTEST_MAIN(tst_Yaml)
+
+#include "tst_yaml.moc"
diff --git a/tests/yaml/yaml.pro b/tests/yaml/yaml.pro
new file mode 100644
index 00000000..5cc4bbb5
--- /dev/null
+++ b/tests/yaml/yaml.pro
@@ -0,0 +1,12 @@
+TARGET = tst_yaml
+
+include($$PWD/../tests.pri)
+
+QT *= appman_common-private
+
+SOURCES += tst_yaml.cpp
+
+RESOURCES += \
+ data/test.yaml \
+ data/cache1.yaml \
+ data/cache2.yaml \
diff --git a/util/bash/appman-prompt b/util/bash/appman-prompt
index cd85278f..0538274e 100644
--- a/util/bash/appman-prompt
+++ b/util/bash/appman-prompt
@@ -4,7 +4,7 @@
## Copyright (C) 2018 Pelagicore AG
## Contact: https://www.qt.io/licensing/
##
-## This file is part of the Luxoft Application Manager.
+## This file is part of the Qt Application Manager.
##
## $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
## Commercial License Usage
@@ -32,10 +32,10 @@ _appman()
local cur opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
- opts="--app-image-mount-dir --build-config --builtin-apps-manifest-dir -c --clear-config-cache --config-file \
+ opts="--app-image-mount-dir --build-config --builtin-apps-manifest-dir -c --clear-cache --config-file \
--database --dbus --force-multi-process --force-single-process --fullscreen --help -I \
---installed-apps-manifest-dir --load-dummydata --logging-rule --no-config-cache --no-dlt-logging \
---no-fullscreen --no-security --no-ui-watchdog -o --option --qml-debug --recreate-database -r --single-app \
+--installed-apps-manifest-dir --load-dummydata --logging-rule --no-cache --no-dlt-logging \
+--no-fullscreen --no-security --no-ui-watchdog -o --option --qml-debug --single-app \
--slow-animations --verbose --version --wayland-socket-name"
if [[ ${cur} == -* ]] ; then
@@ -44,7 +44,7 @@ _appman()
COMPREPLY=( $( compgen -f -- ${cur}) )
fi
}
-complete -o filenames -F _appman appman
+complete -o filenames -F _appman appman appman-qmltestrunner
_appman-controller()
{