diff options
author | Katja Marttila <katja.marttila@qt.io> | 2020-02-25 11:50:48 +0200 |
---|---|---|
committer | Katja Marttila <katja.marttila@qt.io> | 2020-03-12 07:54:50 +0000 |
commit | d98e8e8b62c90ee867e8f25fabca4f3adeeacbea (patch) | |
tree | 22a48482d17addd7aa786191f711acda8c7770fa | |
parent | 3c7b8025e0db7607ee6ca718a3faf6ddfc677a51 (diff) |
Perform headless commands without GUI dependency
Task-number: QTIFW-1633
Change-Id: I207cd152a471fddd51c152223460f8a9873f4382
Reviewed-by: Iikka Eklund <iikka.eklund@qt.io>
-rw-r--r-- | examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/installscript.qs | 6 | ||||
-rw-r--r-- | examples/registerfileextension/packages/org.qtproject.ifw.example.registerfileextension/meta/installscript.qs | 20 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.cpp | 38 | ||||
-rw-r--r-- | src/sdk/commandlineinterface.cpp | 226 | ||||
-rw-r--r-- | src/sdk/commandlineinterface.h (renamed from src/sdk/updatechecker.h) | 28 | ||||
-rw-r--r-- | src/sdk/installerbase.cpp | 419 | ||||
-rw-r--r-- | src/sdk/installerbase.h | 7 | ||||
-rw-r--r-- | src/sdk/main.cpp | 23 | ||||
-rw-r--r-- | src/sdk/sdk.pro | 4 | ||||
-rw-r--r-- | src/sdk/sdkapp.h | 237 | ||||
-rw-r--r-- | src/sdk/updatechecker.cpp | 116 |
11 files changed, 602 insertions, 522 deletions
diff --git a/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/installscript.qs b/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/installscript.qs index e644afbe6..2cd5e8728 100644 --- a/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/installscript.qs +++ b/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/installscript.qs @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. @@ -52,8 +52,8 @@ Component.prototype.installationFinished = function() { try { if (installer.isInstaller() && installer.status == QInstaller.Success) { - var isReadMeCheckBoxChecked = component.userInterface( "ReadMeCheckBoxForm" ).readMeCheckBox.checked; - if (isReadMeCheckBoxChecked) { + var checkboxForm = component.userInterface( "ReadMeCheckBoxForm" ); + if (checkboxForm && checkboxForm.readMeCheckBox.checked) { QDesktopServices.openUrl("file:///" + installer.value("TargetDir") + "/README.txt"); } } diff --git a/examples/registerfileextension/packages/org.qtproject.ifw.example.registerfileextension/meta/installscript.qs b/examples/registerfileextension/packages/org.qtproject.ifw.example.registerfileextension/meta/installscript.qs index a5a6bb174..aa3fa3a67 100644 --- a/examples/registerfileextension/packages/org.qtproject.ifw.example.registerfileextension/meta/installscript.qs +++ b/examples/registerfileextension/packages/org.qtproject.ifw.example.registerfileextension/meta/installscript.qs @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. @@ -49,9 +49,10 @@ addRegisterFileCheckBox = function() { // don't show when updating or uninstalling if (installer.isInstaller()) { - installer.addWizardPageItem(component, "RegisterFileCheckBoxForm", QInstaller.TargetDirectory); - component.userInterface("RegisterFileCheckBoxForm").RegisterFileCheckBox.text = - component.userInterface("RegisterFileCheckBoxForm").RegisterFileCheckBox.text + component.unusualFileType; + if (installer.addWizardPageItem(component, "RegisterFileCheckBoxForm", QInstaller.TargetDirectory)) { + component.userInterface("RegisterFileCheckBoxForm").RegisterFileCheckBox.text = + component.userInterface("RegisterFileCheckBoxForm").RegisterFileCheckBox.text + component.unusualFileType; + } } } @@ -61,7 +62,9 @@ Component.prototype.createOperations = function() // call default implementation to actually install the registeredfile component.createOperations(); - var isRegisterFileChecked = component.userInterface("RegisterFileCheckBoxForm").RegisterFileCheckBox.checked; + if (component.userInterface("RegisterFileCheckBoxForm")) { + var isRegisterFileChecked = component.userInterface("RegisterFileCheckBoxForm").RegisterFileCheckBox.checked; + } if (installer.value("os") === "win") { var iconId = 0; var notepadPath = installer.environmentVariable("SystemRoot") + "\\notepad.exe"; @@ -93,8 +96,9 @@ openRegisteredFileIfChecked = function() addOpenFileCheckBoxToFinishPage = function() { if (installer.isInstaller() && installer.status == QInstaller.Success) { - installer.addWizardPageItem(component, "OpenFileCheckBoxForm", QInstaller.InstallationFinished); - component.userInterface("OpenFileCheckBoxForm").OpenRegisteredFileCheckBox.text = - component.userInterface("OpenFileCheckBoxForm").OpenRegisteredFileCheckBox.text + component.unusualFileType; + if (installer.addWizardPageItem(component, "OpenFileCheckBoxForm", QInstaller.InstallationFinished)) { + component.userInterface("OpenFileCheckBoxForm").OpenRegisteredFileCheckBox.text = + component.userInterface("OpenFileCheckBoxForm").OpenRegisteredFileCheckBox.text + component.unusualFileType; + } } } diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index 878737dc1..36c9935ce 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -1453,9 +1453,13 @@ bool PackageManagerCore::fetchPackagesTree(const PackagesList &packages, const L */ bool PackageManagerCore::addWizardPage(Component *component, const QString &name, int page) { - if (QWidget* const widget = component->userInterface(name)) { - emit wizardPageInsertionRequested(widget, static_cast<WizardPage>(page)); - return true; + if (!isCommandLineInstance()) { + if (QWidget* const widget = component->userInterface(name)) { + emit wizardPageInsertionRequested(widget, static_cast<WizardPage>(page)); + return true; + } + } else { + qCDebug(QInstaller::lcGeneral) << "Headless installation: skip wizard page addition: " << name; } return false; } @@ -1473,9 +1477,13 @@ bool PackageManagerCore::addWizardPage(Component *component, const QString &name */ bool PackageManagerCore::removeWizardPage(Component *component, const QString &name) { - if (QWidget* const widget = component->userInterface(name)) { - emit wizardPageRemovalRequested(widget); - return true; + if (!isCommandLineInstance()) { + if (QWidget* const widget = component->userInterface(name)) { + emit wizardPageRemovalRequested(widget); + return true; + } + } else { + qCDebug(QInstaller::lcGeneral) << "Headless installation: skip wizard page removal: " << name; } return false; } @@ -1533,9 +1541,13 @@ void PackageManagerCore::setValidatorForCustomPage(Component *component, const Q */ bool PackageManagerCore::addWizardPageItem(Component *component, const QString &name, int page) { - if (QWidget* const widget = component->userInterface(name)) { - emit wizardWidgetInsertionRequested(widget, static_cast<WizardPage>(page)); - return true; + if (!isCommandLineInstance()) { + if (QWidget* const widget = component->userInterface(name)) { + emit wizardWidgetInsertionRequested(widget, static_cast<WizardPage>(page)); + return true; + } + } else { + qCDebug(QInstaller::lcGeneral) << "Headless installation: skip wizard page item addition: " << name; } return false; } @@ -1554,9 +1566,11 @@ bool PackageManagerCore::addWizardPageItem(Component *component, const QString & */ bool PackageManagerCore::removeWizardPageItem(Component *component, const QString &name) { - if (QWidget* const widget = component->userInterface(name)) { - emit wizardWidgetRemovalRequested(widget); - return true; + if (!isCommandLineInstance()) { + if (QWidget* const widget = component->userInterface(name)) { + emit wizardWidgetRemovalRequested(widget); + return true; + } } return false; } diff --git a/src/sdk/commandlineinterface.cpp b/src/sdk/commandlineinterface.cpp new file mode 100644 index 000000000..26c4d216c --- /dev/null +++ b/src/sdk/commandlineinterface.cpp @@ -0,0 +1,226 @@ +/************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Installer Framework. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +**************************************************************************/ + +#include "commandlineinterface.h" + +#include <component.h> +#include <init.h> +#include <packagemanagercore.h> +#include <globals.h> +#include <productkeycheck.h> + +#include <QDir> +#include <QDomDocument> + +#include <iostream> + +CommandLineInterface::CommandLineInterface(int &argc, char *argv[]) + : SDKApp<QCoreApplication>(argc, argv) +{ + QInstaller::init(); // register custom operations + m_parser.parse(arguments()); +} + +bool CommandLineInterface::initialize() +{ + QString errorMessage; + if (!init(errorMessage)) { + qCWarning(QInstaller::lcInstallerInstallLog) << errorMessage; + return false; + } + return true; +} + +int CommandLineInterface::checkUpdates() +{ + if (!initialize()) + return EXIT_FAILURE; + if (m_core->isInstaller()) { + qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot start installer binary as updater."; + return EXIT_FAILURE; + } + m_core->setUpdater(); + if (!m_core->fetchRemotePackagesTree()) { + qCWarning(QInstaller::lcInstallerInstallLog) << m_core->error(); + return EXIT_FAILURE; + } + + const QList<QInstaller::Component *> components = + m_core->components(QInstaller::PackageManagerCore::ComponentType::Root); + if (components.isEmpty()) { + qCWarning(QInstaller::lcInstallerInstallLog) << "There are currently no updates available."; + return EXIT_SUCCESS; + } + + QDomDocument doc; + QDomElement root = doc.createElement(QLatin1String("updates")); + doc.appendChild(root); + + foreach (QInstaller::Component *component, components) { + QDomElement update = doc.createElement(QLatin1String("update")); + update.setAttribute(QLatin1String("name"), component->value(QInstaller::scDisplayName)); + update.setAttribute(QLatin1String("version"), component->value(QInstaller::scVersion)); + update.setAttribute(QLatin1String("size"), component->value(QInstaller::scUncompressedSize)); + root.appendChild(update); + } + + std::cout << qPrintable(doc.toString(4)) << std::endl; + return EXIT_SUCCESS; +} + +int CommandLineInterface::silentUpdate() +{ + if (!initialize()) + return EXIT_FAILURE; + if (m_core->isInstaller()) { + qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot start installer binary as updater."; + return EXIT_FAILURE; + } + if (!checkLicense()) + return EXIT_FAILURE; + m_core->updateComponentsSilently(QStringList()); + return EXIT_SUCCESS; +} + +int CommandLineInterface::listInstalledPackages() +{ + if (!initialize()) + return EXIT_FAILURE; + if (m_core->isInstaller()) { + qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot start installer binary as package manager."; + return EXIT_FAILURE; + } + m_core->setPackageManager(); + m_core->listInstalledPackages(); + return EXIT_SUCCESS; +} + +int CommandLineInterface::listAvailablePackages() +{ + if (!initialize()) + return EXIT_FAILURE; + if (!m_core->isInstaller()) + m_core->setPackageManager(); + if (!checkLicense()) + return EXIT_FAILURE; + QString regexp = m_parser.value(QLatin1String(CommandLineOptions::ListPackages)); + m_core->listAvailablePackages(regexp); + return EXIT_SUCCESS; +} + +int CommandLineInterface::updatePackages() +{ + if (!initialize()) + return EXIT_FAILURE; + if (m_core->isInstaller()) { + qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot start installer binary as updater."; + return EXIT_FAILURE; + } + if (!checkLicense()) + return EXIT_FAILURE; + QStringList packages; + const QString &value = m_parser.value(QLatin1String(CommandLineOptions::UpdatePackages)); + if (!value.isEmpty()) + packages = value.split(QLatin1Char(','), QString::SkipEmptyParts); + m_core->updateComponentsSilently(packages); + return EXIT_SUCCESS; +} + +int CommandLineInterface::install() +{ + if (!initialize() || (m_core->isInstaller() && !setTargetDir()) || !checkLicense()) + return EXIT_FAILURE; + QStringList packages; + const QString &value = m_parser.value(QLatin1String(CommandLineOptions::InstallPackages)); + if (!value.isEmpty()) + packages = value.split(QLatin1Char(','), QString::SkipEmptyParts); + m_core->installSelectedComponentsSilently(packages); + return EXIT_SUCCESS; +} + +int CommandLineInterface::installDefault() +{ + if (!initialize()) + return EXIT_FAILURE; + if (!m_core->isInstaller()) { + qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot start installer binary as updater."; + return EXIT_FAILURE; + } + if (!setTargetDir() || !checkLicense()) + return EXIT_FAILURE; + m_core->installDefaultComponentsSilently(); + return EXIT_SUCCESS; +} + +int CommandLineInterface::uninstallPackages() +{ + if (!initialize()) + return EXIT_FAILURE; + if (m_core->isInstaller()) { + qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot start installer binary as package manager."; + return EXIT_FAILURE; + } + m_core->setPackageManager(); + QStringList packages; + const QString &value = m_parser.value(QLatin1String(CommandLineOptions::UninstallSelectedPackages)); + if (!value.isEmpty()) + packages = value.split(QLatin1Char(','), QString::SkipEmptyParts); + m_core->uninstallComponentsSilently(packages); + return EXIT_SUCCESS; +} + +bool CommandLineInterface::checkLicense() +{ + const ProductKeyCheck *const productKeyCheck = ProductKeyCheck::instance(); + if (!productKeyCheck->hasValidLicense()) { + qCWarning(QInstaller::lcPackageLicenses) << "No valid license found."; + return false; + } + return true; +} + +bool CommandLineInterface::setTargetDir() +{ + QString targetDir; + if (m_parser.isSet(QLatin1String(CommandLineOptions::TargetDir))) { + targetDir = m_parser.value(QLatin1String(CommandLineOptions::TargetDir)); + } else { + targetDir = m_core->value(QLatin1String("TargetDir")); + qCDebug(QInstaller::lcInstallerInstallLog) << "No target directory specified, using default value:" << targetDir; + } + if (m_core->checkTargetDir(targetDir)) { + QString targetDirWarning = m_core->targetDirWarning(targetDir); + if (!targetDirWarning.isEmpty()) { + qCWarning(QInstaller::lcInstallerInstallLog) << m_core->targetDirWarning(targetDir); + } else { + m_core->setValue(QLatin1String("TargetDir"), targetDir); + return true; + } + } + return false; +} diff --git a/src/sdk/updatechecker.h b/src/sdk/commandlineinterface.h index d6bdef025..d68c5fc31 100644 --- a/src/sdk/updatechecker.h +++ b/src/sdk/commandlineinterface.h @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -26,19 +26,31 @@ ** **************************************************************************/ -#ifndef UPDATECHECKER_H -#define UPDATECHECKER_H +#ifndef COMMANDLINEINTERFACE_H +#define COMMANDLINEINTERFACE_H #include "sdkapp.h" -class UpdateChecker : public SDKApp<QCoreApplication> +class CommandLineInterface : public SDKApp<QCoreApplication> { Q_OBJECT - Q_DISABLE_COPY(UpdateChecker) + Q_DISABLE_COPY(CommandLineInterface) public: - UpdateChecker(int &argc, char *argv[]); - int check(); + CommandLineInterface(int &argc, char *argv[]); + int checkUpdates(); + int silentUpdate(); + int listInstalledPackages(); + int listAvailablePackages(); + int updatePackages(); + int install(); + int installDefault(); + int uninstallPackages(); + +private: + bool initialize(); + bool checkLicense(); + bool setTargetDir(); }; -#endif // UPDATECHECKER_H +#endif // COMMANDLINEINTERFACE_H diff --git a/src/sdk/installerbase.cpp b/src/sdk/installerbase.cpp index e1b553b83..3cc5db5a5 100644 --- a/src/sdk/installerbase.cpp +++ b/src/sdk/installerbase.cpp @@ -26,37 +26,21 @@ ** **************************************************************************/ -#include "commandlineparser.h" #include "installerbase.h" + #include "installerbasecommons.h" #include "tabcontroller.h" -#include <binaryformatenginehandler.h> -#include <copydirectoryoperation.h> -#include <errors.h> #include <init.h> -#include <updateoperations.h> #include <messageboxhandler.h> #include <packagemanagercore.h> -#include <packagemanagerproxyfactory.h> -#include <qprocesswrapper.h> -#include <protocol.h> -#include <productkeycheck.h> -#include <settings.h> -#include <utils.h> #include <globals.h> -#include <constants.h> - #include <runoncechecker.h> -#include <filedownloaderfactory.h> #include <QDir> #include <QDirIterator> #include <QFontDatabase> -#include <QTemporaryFile> #include <QTranslator> -#include <QUuid> -#include <QLoggingCategory> #ifdef ENABLE_SQUISH #include <qtbuiltinhook.h> @@ -64,7 +48,6 @@ InstallerBase::InstallerBase(int &argc, char *argv[]) : SDKApp<QApplication>(argc, argv) - , m_core(nullptr) { QInstaller::init(); // register custom operations } @@ -76,224 +59,35 @@ InstallerBase::~InstallerBase() int InstallerBase::run() { - RunOnceChecker runCheck(QDir::tempPath() - + QLatin1Char('/') - + qApp->applicationName() - + QLatin1String("1234865.lock")); - if (runCheck.isRunning(RunOnceChecker::ConditionFlag::Lockfile)) { - // It is possible that two installers with the same name get executed - // concurrently and thus try to access the same lock file. This causes - // a warning to be shown (when verbose output is enabled) but let's - // just silently ignore the fact that we could not create the lock file - // and check the running processes. - if (runCheck.isRunning(RunOnceChecker::ConditionFlag::ProcessList)) { - QInstaller::MessageBoxHandler::information(nullptr, QLatin1String("AlreadyRunning"), - tr("Waiting for %1").arg(qAppName()), - tr("Another %1 instance is already running. Wait " - "until it finishes, close it, or restart your system.").arg(qAppName())); - return EXIT_FAILURE; - } - } - - QFile binary(binaryFile()); - -#ifdef Q_OS_WIN - // On some admin user installations it is possible that the installer.dat - // file is left without reading permissions for non-administrator users, - // we should check this and prompt the user to run the executable as admin if needed. - if (!binary.open(QIODevice::ReadOnly)) { - QFileInfo binaryInfo(binary.fileName()); - QInstaller::MessageBoxHandler::information(nullptr, QLatin1String("NoReadingPermissions"), - tr("Cannot open file \"%1\" for reading").arg(binaryInfo.fileName()), - tr("Please make sure that the current user has reading access " - "to file \"%1\" or try running %2 as an administrator.").arg(binaryInfo.fileName(), qAppName())); + QString errorMessage; + if (!init(errorMessage)) { + QInstaller::MessageBoxHandler::information(nullptr, QLatin1String("UnableToStart"), + tr("Unable to start installer"), errorMessage); return EXIT_FAILURE; } - binary.close(); -#endif - QString fileName = datFile(binaryFile()); - quint64 cookie = QInstaller::BinaryContent::MagicCookieDat; - if (fileName.isEmpty()) { - fileName = binaryFile(); - cookie = QInstaller::BinaryContent::MagicCookie; - } - - binary.setFileName(fileName); - QInstaller::openForRead(&binary); - - qint64 magicMarker; - QInstaller::ResourceCollectionManager manager; - QList<QInstaller::OperationBlob> oldOperations; - QInstaller::BinaryContent::readBinaryContent(&binary, &oldOperations, &manager, &magicMarker, - cookie); - - // Usually resources simply get mapped into memory and therefore the file does not need to be - // kept open during application runtime. Though in case of offline installers we need to access - // the appended binary content (packages etc.), so we close only in maintenance mode. - if (magicMarker != QInstaller::BinaryContent::MagicInstallerMarker) - binary.close(); - - CommandLineParser parser; - parser.parse(arguments()); - QString loggingRules(QLatin1String("ifw.* = false")); // disable all by default - bool isCliInterface = false; - foreach (const QString &option, CommandLineOptions::scCommandLineInterfaceOptions) { - if (parser.isSet(option)) { - isCliInterface = true; - break; - } + if (m_parser.isSet(QLatin1String(CommandLineOptions::ShowVirtualComponents))) { + QFont f; + f.setItalic(true); + QInstaller::PackageManagerCore::setVirtualComponentsFont(f); } - if (QInstaller::isVerbose()) { - if (parser.isSet(QLatin1String(CommandLineOptions::LoggingRules))) { - loggingRules = parser.value(QLatin1String(CommandLineOptions::LoggingRules)) - .split(QLatin1Char(','), QString::SkipEmptyParts) - .join(QLatin1Char('\n')); // take rules from command line - } else if (isCliInterface) { - loggingRules = QLatin1String("ifw.* = false\n" - "ifw.installer.* = true\n" - "ifw.server = true\n" - "ifw.package.name = true\n" - "ifw.package.version = true\n" - "ifw.package.displayname = true\n"); - } else { - // enable all in verbose mode except detailed package information - loggingRules = QLatin1String("ifw.* = true\n" - "ifw.package.* = false\n" - "ifw.package.name = true\n" - "ifw.package.version = true\n" - "ifw.package.displayname = true\n"); + QString controlScript; + if (m_parser.isSet(QLatin1String(CommandLineOptions::Script))) { + controlScript = m_parser.value(QLatin1String(CommandLineOptions::Script)); + if (!QFileInfo(controlScript).exists()) { + qCDebug(QInstaller::lcInstallerInstallLog) << "Script file does not exist."; + return false; } - } - QLoggingCategory::setFilterRules(loggingRules); - - qCDebug(QInstaller::lcTranslations) << "Language:" << QLocale().uiLanguages() - .value(0, QLatin1String("No UI language set")).toUtf8().constData(); - qCDebug(QInstaller::lcInstallerInstallLog).noquote() << "Arguments:" << arguments().join(QLatin1String(", ")); - SDKApp::registerMetaResources(manager.collectionByName("QResources")); - if (parser.isSet(QLatin1String(CommandLineOptions::StartClient))) { - const QStringList arguments = parser.value(QLatin1String(CommandLineOptions::StartClient)) - .split(QLatin1Char(','), QString::SkipEmptyParts); - m_core = new QInstaller::PackageManagerCore( - magicMarker, oldOperations, - arguments.value(0, QLatin1String(QInstaller::Protocol::DefaultSocket)), - arguments.value(1, QLatin1String(QInstaller::Protocol::DefaultAuthorizationKey)), - QInstaller::Protocol::Mode::Debug); - } else { - m_core = new QInstaller::PackageManagerCore(magicMarker, oldOperations, - QUuid::createUuid().toString(), QUuid::createUuid().toString()); - m_core->setCommandLineInstance(isCliInterface); - } - - { - using namespace QInstaller; - ProductKeyCheck::instance()->init(m_core); - ProductKeyCheck::instance()->addPackagesFromXml(QLatin1String(":/metadata/Updates.xml")); - BinaryFormatEngineHandler::instance()->registerResources(manager.collections()); - } - - dumpResourceTree(); - - QString controlScript; - if (parser.isSet(QLatin1String(CommandLineOptions::Script))) { - controlScript = parser.value(QLatin1String(CommandLineOptions::Script)); - if (!QFileInfo(controlScript).exists()) - throw QInstaller::Error(QLatin1String("Script file does not exist.")); } else if (!m_core->settings().controlScript().isEmpty()) { controlScript = QLatin1String(":/metadata/installer-config/") + m_core->settings().controlScript(); } + qCDebug(QInstaller::lcTranslations) << "Language:" << QLocale().uiLanguages() + .value(0, QLatin1String("No UI language set")).toUtf8().constData(); + qCDebug(QInstaller::lcInstallerInstallLog).noquote() << "Arguments:" << arguments().join(QLatin1String(", ")); - // From Qt5.8 onwards a separate command line option --proxy is not needed as system - // proxy is used by default. If Qt is built with QT_USE_SYSTEM_PROXIES false - // then system proxies are not used by default. - if (parser.isSet(QLatin1String(CommandLineOptions::NoProxy))) { - m_core->settings().setProxyType(QInstaller::Settings::NoProxy); - KDUpdater::FileDownloaderFactory::instance().setProxyFactory(m_core->proxyFactory()); - } else if ((parser.isSet(QLatin1String(CommandLineOptions::Proxy)) - || QNetworkProxyFactory::usesSystemConfiguration())) { - m_core->settings().setProxyType(QInstaller::Settings::SystemProxy); - KDUpdater::FileDownloaderFactory::instance().setProxyFactory(m_core->proxyFactory()); - } - - if (parser.isSet(QLatin1String(CommandLineOptions::ShowVirtualComponents))) { - QFont f; - f.setItalic(true); - QInstaller::PackageManagerCore::setVirtualComponentsFont(f); - QInstaller::PackageManagerCore::setVirtualComponentsVisible(true); - } - - if (parser.isSet(QLatin1String(CommandLineOptions::Updater))) { - if (m_core->isInstaller()) - throw QInstaller::Error(QLatin1String("Cannot start installer binary as updater.")); - m_core->setUserSetBinaryMarker(QInstaller::BinaryContent::MagicUpdaterMarker); - } - - if (parser.isSet(QLatin1String(CommandLineOptions::ManagePackages))) { - if (m_core->isInstaller()) - throw QInstaller::Error(QLatin1String("Cannot start installer binary as package manager.")); - m_core->setUserSetBinaryMarker(QInstaller::BinaryContent::MagicPackageManagerMarker); - } - - if (parser.isSet(QLatin1String(CommandLineOptions::Uninstaller))) { - if (m_core->isInstaller()) - throw QInstaller::Error(QLatin1String("Cannot start installer binary as uninstaller.")); - m_core->setUserSetBinaryMarker(QInstaller::BinaryContent::MagicUninstallerMarker); - } - - if (parser.isSet(QLatin1String(CommandLineOptions::AddRepository))) { - const QStringList repoList = repositories(parser - .value(QLatin1String(CommandLineOptions::AddRepository))); - if (repoList.isEmpty()) - throw QInstaller::Error(QLatin1String("Empty repository list for option 'addRepository'.")); - m_core->addUserRepositories(repoList); - } - - if (parser.isSet(QLatin1String(CommandLineOptions::AddTmpRepository))) { - const QStringList repoList = repositories(parser - .value(QLatin1String(CommandLineOptions::AddTmpRepository))); - if (repoList.isEmpty()) - throw QInstaller::Error(QLatin1String("Empty repository list for option 'addTempRepository'.")); - m_core->setTemporaryRepositories(repoList, false); - } - - if (parser.isSet(QLatin1String(CommandLineOptions::SetTmpRepository))) { - const QStringList repoList = repositories(parser - .value(QLatin1String(CommandLineOptions::SetTmpRepository))); - if (repoList.isEmpty()) - throw QInstaller::Error(QLatin1String("Empty repository list for option 'setTempRepository'.")); - m_core->setTemporaryRepositories(repoList, true); - } - - if (parser.isSet(QLatin1String(CommandLineOptions::InstallCompressedRepository))) { - const QStringList repoList = repositories(parser - .value(QLatin1String(CommandLineOptions::InstallCompressedRepository))); - if (repoList.isEmpty()) - throw QInstaller::Error(QLatin1String("Empty repository list for option 'installCompressedRepository'.")); - foreach (QString repository, repoList) { - if (!QFileInfo::exists(repository)) { - qCWarning(QInstaller::lcInstallerInstallLog) << "The file " << repository << "does not exist."; - return EXIT_FAILURE; - } - } - m_core->setTemporaryRepositories(repoList, false, true); - } - - QInstaller::PackageManagerCore::setNoForceInstallation(parser - .isSet(QLatin1String(CommandLineOptions::NoForceInstallation))); - QInstaller::PackageManagerCore::setCreateLocalRepositoryFromBinary(parser - .isSet(QLatin1String(CommandLineOptions::CreateLocalRepository)) - || m_core->settings().createLocalRepository()); - - const QStringList positionalArguments = parser.positionalArguments(); - foreach (const QString &argument, positionalArguments) { - if (argument.contains(QLatin1Char('='))) { - const QString name = argument.section(QLatin1Char('='), 0, 0); - const QString value = argument.section(QLatin1Char('='), 1, 1); - m_core->setValue(name, value); - } - } + dumpResourceTree(); const QString directory = QLatin1String(":/translations"); const QStringList translations = m_core->settings().translations(); @@ -334,113 +128,54 @@ int InstallerBase::run() qCWarning(QInstaller::lcInstallerInstallLog) << "Failed to register font!"; } } + //create the wizard GUI + TabController controller(nullptr); + controller.setManager(m_core); + controller.setControlScript(controlScript); + if (m_core->isInstaller()) + controller.setGui(new InstallerGui(m_core)); + else + controller.setGui(new MaintenanceGui(m_core)); - if (parser.isSet(QLatin1String(CommandLineOptions::SilentUpdate))) { - if (m_core->isInstaller()) - throw QInstaller::Error(QLatin1String("Cannot start installer binary as updater.")); - checkLicense(); - m_core->updateComponentsSilently(QStringList()); - } else if (parser.isSet(QLatin1String(CommandLineOptions::ListInstalledPackages))){ - if (m_core->isInstaller()) - throw QInstaller::Error(QLatin1String("Cannot start installer binary as package manager.")); - checkLicense(); - m_core->setPackageManager(); - m_core->listInstalledPackages(); - } else if (parser.isSet(QLatin1String(CommandLineOptions::ListPackages))){ - if (!m_core->isInstaller()) - m_core->setPackageManager(); - checkLicense(); - QString regexp = parser.value(QLatin1String(CommandLineOptions::ListPackages)); - m_core->listAvailablePackages(regexp); - } else if (parser.isSet(QLatin1String(CommandLineOptions::UpdatePackages))) { - if (m_core->isInstaller()) - throw QInstaller::Error(QLatin1String("Cannot start installer binary as updater.")); - checkLicense(); - QStringList packages; - const QString &value = parser.value(QLatin1String(CommandLineOptions::UpdatePackages)); - if (!value.isEmpty()) - packages = value.split(QLatin1Char(','), QString::SkipEmptyParts); - m_core->updateComponentsSilently(packages); - } else if (parser.isSet(QLatin1String(CommandLineOptions::InstallPackages))) { - checkLicense(); - m_core->autoRejectMessageBoxes(); - if (m_core->isInstaller()) { - if (!setTargetDirForCommandLineInterface(parser)) - return EXIT_FAILURE; - } - - QStringList packages; - const QString &value = parser.value(QLatin1String(CommandLineOptions::InstallPackages)); - if (!value.isEmpty()) - packages = value.split(QLatin1Char(','), QString::SkipEmptyParts); - m_core->installSelectedComponentsSilently(packages); - } else if (parser.isSet(QLatin1String(CommandLineOptions::InstallDefault))) { - if (!m_core->isInstaller()) - throw QInstaller::Error(QLatin1String("Cannot start installer binary as installer.")); - checkLicense(); - m_core->autoRejectMessageBoxes(); - if (!setTargetDirForCommandLineInterface(parser)) - return EXIT_FAILURE; - m_core->installDefaultComponentsSilently(); - } else if (parser.isSet(QLatin1String(CommandLineOptions::UninstallSelectedPackages))) { - if (m_core->isInstaller()) - throw QInstaller::Error(QLatin1String("Cannot start installer binary as package manager.")); - m_core->setPackageManager(); - QStringList packages; - const QString &value = parser.value(QLatin1String(CommandLineOptions::UninstallSelectedPackages)); - if (!value.isEmpty()) - packages = value.split(QLatin1Char(','), QString::SkipEmptyParts); - m_core->uninstallComponentsSilently(packages); - } else { - //create the wizard GUI - TabController controller(nullptr); - controller.setManager(m_core); - controller.setControlScript(controlScript); - if (m_core->isInstaller()) - controller.setGui(new InstallerGui(m_core)); - else - controller.setGui(new MaintenanceGui(m_core)); - - QInstaller::PackageManagerCore::Status status = - QInstaller::PackageManagerCore::Status(controller.init()); - if (status != QInstaller::PackageManagerCore::Success) - return status; + QInstaller::PackageManagerCore::Status status = + QInstaller::PackageManagerCore::Status(controller.init()); + if (status != QInstaller::PackageManagerCore::Success) + return status; #ifdef ENABLE_SQUISH - int squishPort = 11233; - if (parser.isSet(QLatin1String(CommandLineOptions::SquishPort))) { - squishPort = parser.value(QLatin1String(CommandLineOptions::SquishPort)).toInt(); - } - if (squishPort != 0) { - if (Squish::allowAttaching(squishPort)) - qCDebug(QInstaller::lcGeneral) << "Attaching to squish port " << squishPort << " succeeded"; - else - qCDebug(QInstaller::lcGeneral) << "Attaching to squish failed."; - } else { - qCWarning(QInstaller::lcGeneral) << "Invalid squish port number: " << squishPort; - } + int squishPort = 11233; + if (m_parser.isSet(QLatin1String(CommandLineOptions::SquishPort))) { + squishPort = m_parser.value(QLatin1String(CommandLineOptions::SquishPort)).toInt(); + } + if (squishPort != 0) { + if (Squish::allowAttaching(squishPort)) + qCDebug(QInstaller::lcGeneral) << "Attaching to squish port " << squishPort << " succeeded"; + else + qCDebug(QInstaller::lcGeneral) << "Attaching to squish failed."; + } else { + qCWarning(QInstaller::lcGeneral) << "Invalid squish port number: " << squishPort; + } #endif - const int result = QCoreApplication::instance()->exec(); - if (result != 0) - return result; + const int result = QCoreApplication::instance()->exec(); + if (result != 0) + return result; - if (m_core->finishedWithSuccess()) - return QInstaller::PackageManagerCore::Success; + if (m_core->finishedWithSuccess()) + return QInstaller::PackageManagerCore::Success; - status = m_core->status(); - switch (status) { - case QInstaller::PackageManagerCore::Success: - return status; + status = m_core->status(); + switch (status) { + case QInstaller::PackageManagerCore::Success: + return status; - case QInstaller::PackageManagerCore::Canceled: - return status; + case QInstaller::PackageManagerCore::Canceled: + return status; - default: - break; - } - return QInstaller::PackageManagerCore::Failure; + default: + break; } - return QInstaller::PackageManagerCore::Success; + return QInstaller::PackageManagerCore::Failure; + } @@ -457,41 +192,3 @@ void InstallerBase::dumpResourceTree() const qCDebug(QInstaller::lcResources) << " " << it.filePath().toUtf8().constData(); } } - -QStringList InstallerBase::repositories(const QString &list) const -{ - const QStringList items = list.split(QLatin1Char(','), QString::SkipEmptyParts); - foreach (const QString &item, items) - qCDebug(QInstaller::lcInstallerInstallLog).noquote() << "Adding custom repository:" << item; - return items; -} - -void InstallerBase::checkLicense() -{ - const ProductKeyCheck *const productKeyCheck = ProductKeyCheck::instance(); - if (!productKeyCheck->hasValidLicense()) { - qCWarning(QInstaller::lcPackageLicenses) << "No valid license found."; - throw QInstaller::Error(QLatin1String("No valid license found.")); - } -} - -bool InstallerBase::setTargetDirForCommandLineInterface(CommandLineParser &parser) -{ - QString targetDir; - if (parser.isSet(QLatin1String(CommandLineOptions::TargetDir))) { - targetDir = parser.value(QLatin1String(CommandLineOptions::TargetDir)); - } else { - targetDir = m_core->value(QLatin1String("TargetDir")); - qCDebug(QInstaller::lcInstallerInstallLog) << "No target directory specified, using default value:" << targetDir; - } - if (m_core->checkTargetDir(targetDir)) { - QString targetDirWarning = m_core->targetDirWarning(targetDir); - if (!targetDirWarning.isEmpty()) { - qCWarning(QInstaller::lcInstallerInstallLog) << m_core->targetDirWarning(targetDir); - } else { - m_core->setValue(QLatin1String("TargetDir"), targetDir); - return true; - } - } - return false; -} diff --git a/src/sdk/installerbase.h b/src/sdk/installerbase.h index a23a7856d..2efb6276e 100644 --- a/src/sdk/installerbase.h +++ b/src/sdk/installerbase.h @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -50,11 +50,6 @@ public: private: void dumpResourceTree() const; QStringList repositories(const QString &list) const; - void checkLicense(); - bool setTargetDirForCommandLineInterface(CommandLineParser &parser); - -private: - QInstaller::PackageManagerCore *m_core; }; #endif // INSTALLERBASE_H diff --git a/src/sdk/main.cpp b/src/sdk/main.cpp index c2b5c9f01..5ce0615c7 100644 --- a/src/sdk/main.cpp +++ b/src/sdk/main.cpp @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -31,7 +31,7 @@ #include "commandlineparser.h" #include "installerbase.h" #include "sdkapp.h" -#include "updatechecker.h" +#include "commandlineinterface.h" #include <errors.h> #include <selfrestarter.h> @@ -216,13 +216,28 @@ int main(int argc, char *argv[]) if (parser.isSet(QLatin1String(CommandLineOptions::NoProxy))) QNetworkProxyFactory::setUseSystemConfiguration(false); + const SelfRestarter restarter(argc, argv); + if (parser.isSet(QLatin1String(CommandLineOptions::CheckUpdates))) - return UpdateChecker(argc, argv).check(); + return CommandLineInterface(argc, argv).checkUpdates(); + if (parser.isSet(QLatin1String(CommandLineOptions::SilentUpdate))) + return CommandLineInterface(argc, argv).silentUpdate(); + if (parser.isSet(QLatin1String(CommandLineOptions::ListInstalledPackages))) + return CommandLineInterface(argc, argv).listInstalledPackages(); + if (parser.isSet(QLatin1String(CommandLineOptions::ListPackages))) + return CommandLineInterface(argc, argv).listAvailablePackages(); + if (parser.isSet(QLatin1String(CommandLineOptions::UpdatePackages))) + return CommandLineInterface(argc, argv).updatePackages(); + if (parser.isSet(QLatin1String(CommandLineOptions::InstallPackages))) + return CommandLineInterface(argc, argv).install(); + if (parser.isSet(QLatin1String(CommandLineOptions::InstallDefault))) + return CommandLineInterface(argc, argv).installDefault(); + if (parser.isSet(QLatin1String(CommandLineOptions::UninstallSelectedPackages))) + return CommandLineInterface(argc, argv).uninstallPackages(); if (QInstaller::isVerbose()) std::cout << VERSION << std::endl << BUILDDATE << std::endl << SHA << std::endl; - const SelfRestarter restarter(argc, argv); return InstallerBase(argc, argv).run(); } catch (const QInstaller::Error &e) { diff --git a/src/sdk/sdk.pro b/src/sdk/sdk.pro index 04c1c5016..08d08db39 100644 --- a/src/sdk/sdk.pro +++ b/src/sdk/sdk.pro @@ -100,7 +100,7 @@ HEADERS += \ settingsdialog.h \ console.h \ sdkapp.h \ - updatechecker.h \ + commandlineinterface.h \ installerbase.h \ commandlineparser.h @@ -110,7 +110,7 @@ SOURCES = \ tabcontroller.cpp \ installerbasecommons.cpp \ settingsdialog.cpp \ - updatechecker.cpp \ + commandlineinterface.cpp \ commandlineparser.cpp win32 { diff --git a/src/sdk/sdkapp.h b/src/sdk/sdkapp.h index 68d7a2434..235486086 100644 --- a/src/sdk/sdkapp.h +++ b/src/sdk/sdkapp.h @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -29,23 +29,39 @@ #ifndef SDKAPP_H #define SDKAPP_H +#include "commandlineparser.h" + #include <binarycontent.h> #include <binaryformat.h> #include <fileio.h> #include <fileutils.h> +#include <constants.h> +#include <packagemanagercore.h> +#include <settings.h> +#include <productkeycheck.h> +#include <binaryformatenginehandler.h> +#include <filedownloaderfactory.h> +#include <packagemanagerproxyfactory.h> +#include <utils.h> +#include <runoncechecker.h> +#include <globals.h> #include <QApplication> #include <QDir> #include <QFileInfo> #include <QResource> +#include <QLoggingCategory> +#include <QUuid> template<class T> class SDKApp : public T { public: SDKApp(int& argc, char** argv) - : T(argc, argv) + : T(argc, argv), m_runCheck(QDir::tempPath() + QLatin1Char('/') + + qApp->applicationName() + QLatin1String("1234865.lock")) { + m_parser.parse(QCoreApplication::arguments()); } virtual ~SDKApp() @@ -66,6 +82,210 @@ public: return false; } + bool init(QString &errorMessage) { + QString appname = qApp->applicationName(); + + if (m_runCheck.isRunning(RunOnceChecker::ConditionFlag::Lockfile)) { + // It is possible to install an application and thus the maintenance tool into a + // directory that requires elevated permission to create a lock file. Since this + // cannot be done without requesting credentials from the user, we silently ignore + // the fact that we could not create the lock file and check the running processes. + if (m_runCheck.isRunning(RunOnceChecker::ConditionFlag::ProcessList)) { + errorMessage = QObject::tr("Another %1 instance is already running. Wait " + "until it finishes, close it, or restart your system.").arg(qAppName()); + return false; + } + } + QFile binary(binaryFile()); + #ifdef Q_OS_WIN + // On some admin user installations it is possible that the installer.dat + // file is left without reading permissions for non-administrator users, + // we should check this and prompt the user to run the executable as admin if needed. + if (!binary.open(QIODevice::ReadOnly)) { + QFileInfo binaryInfo(binary.fileName()); + errorMessage = QObject::tr("Please make sure that the current user has reading access " + "to file \"%1\" or try running %2 as an administrator.").arg(binaryInfo.fileName(), qAppName()); + return false; + } + binary.close(); + #endif + QString fileName = datFile(binaryFile()); + quint64 cookie = QInstaller::BinaryContent::MagicCookieDat; + if (fileName.isEmpty()) { + fileName = binaryFile(); + cookie = QInstaller::BinaryContent::MagicCookie; + } + + binary.setFileName(fileName); + QInstaller::openForRead(&binary); + + qint64 magicMarker; + QInstaller::ResourceCollectionManager manager; + QList<QInstaller::OperationBlob> oldOperations; + + QInstaller::BinaryContent::readBinaryContent(&binary, &oldOperations, &manager, &magicMarker, + cookie); + // Usually resources simply get mapped into memory and therefore the file does not need to be + // kept open during application runtime. Though in case of offline installers we need to access + // the appended binary content (packages etc.), so we close only in maintenance mode. + if (magicMarker != QInstaller::BinaryContent::MagicInstallerMarker) + binary.close(); + + QString loggingRules(QLatin1String("ifw.* = false")); // disable all by default + bool isCliInterface = false; + foreach (const QString &option, CommandLineOptions::scCommandLineInterfaceOptions) { + if (m_parser.isSet(option)) { + isCliInterface = true; + break; + } + } + if (QInstaller::isVerbose()) { + if (m_parser.isSet(QLatin1String(CommandLineOptions::LoggingRules))) { + loggingRules = m_parser.value(QLatin1String(CommandLineOptions::LoggingRules)) + .split(QLatin1Char(','), QString::SkipEmptyParts) + .join(QLatin1Char('\n')); // take rules from command line + } else if (isCliInterface) { + loggingRules = QLatin1String("ifw.* = false\n" + "ifw.installer.* = true\n" + "ifw.server = true\n" + "ifw.package.name = true\n" + "ifw.package.version = true\n" + "ifw.package.displayname = true\n"); + } else { + // enable all in verbose mode except detailed package information + loggingRules = QLatin1String("ifw.* = true\n" + "ifw.package.* = false\n" + "ifw.package.name = true\n" + "ifw.package.version = true\n" + "ifw.package.displayname = true\n"); + } + } + QLoggingCategory::setFilterRules(loggingRules); + + SDKApp::registerMetaResources(manager.collectionByName("QResources")); + if (m_parser.isSet(QLatin1String(CommandLineOptions::StartClient))) { + const QStringList arguments = m_parser.value(QLatin1String(CommandLineOptions::StartClient)) + .split(QLatin1Char(','), QString::SkipEmptyParts); + m_core = new QInstaller::PackageManagerCore( + magicMarker, oldOperations, + arguments.value(0, QLatin1String(QInstaller::Protocol::DefaultSocket)), + arguments.value(1, QLatin1String(QInstaller::Protocol::DefaultAuthorizationKey)), + QInstaller::Protocol::Mode::Debug); + } else { + m_core = new QInstaller::PackageManagerCore(magicMarker, oldOperations, + QUuid::createUuid().toString(), QUuid::createUuid().toString()); + m_core->setCommandLineInstance(isCliInterface); + } + + { + using namespace QInstaller; + ProductKeyCheck::instance()->init(m_core); + ProductKeyCheck::instance()->addPackagesFromXml(QLatin1String(":/metadata/Updates.xml")); + BinaryFormatEngineHandler::instance()->registerResources(manager.collections()); + } + + // From Qt5.8 onwards a separate command line option --proxy is not needed as system + // proxy is used by default. If Qt is built with QT_USE_SYSTEM_PROXIES false + // then system proxies are not used by default. + if (m_parser.isSet(QLatin1String(CommandLineOptions::NoProxy))) { + m_core->settings().setProxyType(QInstaller::Settings::NoProxy); + KDUpdater::FileDownloaderFactory::instance().setProxyFactory(m_core->proxyFactory()); + } else if ((m_parser.isSet(QLatin1String(CommandLineOptions::Proxy)) + || QNetworkProxyFactory::usesSystemConfiguration())) { + m_core->settings().setProxyType(QInstaller::Settings::SystemProxy); + KDUpdater::FileDownloaderFactory::instance().setProxyFactory(m_core->proxyFactory()); + } + + if (m_parser.isSet(QLatin1String(CommandLineOptions::ShowVirtualComponents))) + QInstaller::PackageManagerCore::setVirtualComponentsVisible(true); + + if (m_parser.isSet(QLatin1String(CommandLineOptions::Updater))) { + if (m_core->isInstaller()) { + errorMessage = QObject::tr("Cannot start installer binary as updater."); + return false; + } + m_core->setUserSetBinaryMarker(QInstaller::BinaryContent::MagicUpdaterMarker); + } + + if (m_parser.isSet(QLatin1String(CommandLineOptions::ManagePackages))) { + if (m_core->isInstaller()) { + errorMessage = QObject::tr("Cannot start installer binary as package manager."); + return false; + } + m_core->setUserSetBinaryMarker(QInstaller::BinaryContent::MagicPackageManagerMarker); + } + + if (m_parser.isSet(QLatin1String(CommandLineOptions::Uninstaller))) { + if (m_core->isInstaller()) { + errorMessage = QObject::tr("Cannot start installer binary as uninstaller."); + return false; + } + m_core->setUserSetBinaryMarker(QInstaller::BinaryContent::MagicUninstallerMarker); + } + + if (m_parser.isSet(QLatin1String(CommandLineOptions::AddRepository))) { + const QStringList repoList = repositories(m_parser + .value(QLatin1String(CommandLineOptions::AddRepository))); + if (repoList.isEmpty()) { + errorMessage = QObject::tr("Empty repository list for option 'addRepository'."); + return false; + } + m_core->addUserRepositories(repoList); + } + + if (m_parser.isSet(QLatin1String(CommandLineOptions::AddTmpRepository))) { + const QStringList repoList = repositories(m_parser + .value(QLatin1String(CommandLineOptions::AddTmpRepository))); + if (repoList.isEmpty()) { + errorMessage = QObject::tr("Empty repository list for option 'addTempRepository'."); + return false; + } + m_core->setTemporaryRepositories(repoList, false); + } + + if (m_parser.isSet(QLatin1String(CommandLineOptions::SetTmpRepository))) { + const QStringList repoList = repositories(m_parser + .value(QLatin1String(CommandLineOptions::SetTmpRepository))); + if (repoList.isEmpty()) { + errorMessage = QObject::tr("Empty repository list for option 'setTempRepository'."); + return false; + } + m_core->setTemporaryRepositories(repoList, true); + } + + if (m_parser.isSet(QLatin1String(CommandLineOptions::InstallCompressedRepository))) { + const QStringList repoList = repositories(m_parser + .value(QLatin1String(CommandLineOptions::InstallCompressedRepository))); + if (repoList.isEmpty()) { + errorMessage = QObject::tr("Empty repository list for option 'installCompressedRepository'."); + return false; + } + foreach (QString repository, repoList) { + if (!QFileInfo::exists(repository)) { + errorMessage = QObject::tr("The file %1 does not exist.").arg(repository); + return false; + } + } + m_core->setTemporaryRepositories(repoList, false, true); + } + + QInstaller::PackageManagerCore::setNoForceInstallation(m_parser + .isSet(QLatin1String(CommandLineOptions::NoForceInstallation))); + QInstaller::PackageManagerCore::setCreateLocalRepositoryFromBinary(m_parser + .isSet(QLatin1String(CommandLineOptions::CreateLocalRepository)) + || m_core->settings().createLocalRepository()); + + const QStringList positionalArguments = m_parser.positionalArguments(); + foreach (const QString &argument, positionalArguments) { + if (argument.contains(QLatin1Char('='))) { + const QString name = argument.section(QLatin1Char('='), 0, 0); + const QString value = argument.section(QLatin1Char('='), 1, 1); + m_core->setValue(name, value); + } + } + return true; + } + /*! Returns the installer binary or installer.dat. In case of an installer this will be the installer binary itself, which contains the binary layout and the binary content. In case @@ -147,8 +367,21 @@ public: } } + QStringList repositories(const QString &list) const + { + const QStringList items = list.split(QLatin1Char(','), QString::SkipEmptyParts); + foreach (const QString &item, items) + qCDebug(QInstaller::lcGeneral) << "Adding custom repository:" << item; + return items; + } + private: QList<QByteArray> m_resourceMappings; + +public: + QInstaller::PackageManagerCore *m_core; + CommandLineParser m_parser; + RunOnceChecker m_runCheck; }; #endif // SDKAPP_H diff --git a/src/sdk/updatechecker.cpp b/src/sdk/updatechecker.cpp deleted file mode 100644 index 63bac8b9f..000000000 --- a/src/sdk/updatechecker.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Installer Framework. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -**************************************************************************/ - -#include "updatechecker.h" - -#include <binaryformatenginehandler.h> -#include <component.h> -#include <errors.h> -#include <init.h> -#include <runoncechecker.h> -#include <packagemanagercore.h> -#include <productkeycheck.h> - -#include <QDir> -#include <QDomDocument> - -#include <iostream> - -UpdateChecker::UpdateChecker(int &argc, char *argv[]) - : SDKApp<QCoreApplication>(argc, argv) -{ - QInstaller::init(); // register custom operations -} - -int UpdateChecker::check() -{ - RunOnceChecker runCheck(QDir::tempPath() - + QLatin1Char('/') - + qApp->applicationName() - + QLatin1String("15021976.lock")); - if (runCheck.isRunning(RunOnceChecker::ConditionFlag::Lockfile)) { - // It is possible to install an application and thus the maintenance tool into a - // directory that requires elevated permission to create a lock file. Since this - // cannot be done without requesting credentials from the user, we silently ignore - // the fact that we could not create the lock file and check the running processes. - if (runCheck.isRunning(RunOnceChecker::ConditionFlag::ProcessList)) - throw QInstaller::Error(QLatin1String("An instance is already checking for updates.")); - } - - QString fileName = datFile(binaryFile()); - quint64 cookie = QInstaller::BinaryContent::MagicCookieDat; - if (fileName.isEmpty()) { - fileName = binaryFile(); - cookie = QInstaller::BinaryContent::MagicCookie; - } - - QFile binary(fileName); - QInstaller::openForRead(&binary); - - qint64 magicMarker; - QList<QInstaller::OperationBlob> operations; - QInstaller::ResourceCollectionManager manager; - QInstaller::BinaryContent::readBinaryContent(&binary, &operations, &manager, &magicMarker, - cookie); - - if (magicMarker == QInstaller::BinaryContent::MagicInstallerMarker) - throw QInstaller::Error(QLatin1String("Installers cannot check for updates.")); - - SDKApp::registerMetaResources(manager.collectionByName("QResources")); - - QInstaller::PackageManagerCore core(QInstaller::BinaryContent::MagicUpdaterMarker, operations); - QInstaller::PackageManagerCore::setVirtualComponentsVisible(true); - { - using namespace QInstaller; - ProductKeyCheck::instance()->init(&core); - ProductKeyCheck::instance()->addPackagesFromXml(QLatin1String(":/metadata/Updates.xml")); - BinaryFormatEngineHandler::instance()->registerResources(manager.collections()); - } - if (!core.fetchRemotePackagesTree()) - throw QInstaller::Error(core.error()); - - const QList<QInstaller::Component *> components = - core.components(QInstaller::PackageManagerCore::ComponentType::Root); - if (components.isEmpty()) - throw QInstaller::Error(QLatin1String("There are currently no updates available.")); - - QDomDocument doc; - QDomElement root = doc.createElement(QLatin1String("updates")); - doc.appendChild(root); - - foreach (QInstaller::Component *component, components) { - QDomElement update = doc.createElement(QLatin1String("update")); - update.setAttribute(QLatin1String("name"), component->value(QInstaller::scDisplayName)); - update.setAttribute(QLatin1String("version"), component->value(QInstaller::scVersion)); - update.setAttribute(QLatin1String("size"), component->value(QInstaller::scUncompressedSize)); - root.appendChild(update); - } - - std::cout << qPrintable(doc.toString(4)) << std::endl; - return EXIT_SUCCESS; -} |