File indexing completed on 2024-03-24 17:22:08

0001 /***************************************************************************
0002  *   Copyright (C) 2009-2011 by Daniel Nicoletti                           *
0003  *   dantti12@gmail.com                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; see the file COPYING. If not, write to       *
0017  *   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,  *
0018  *   Boston, MA 02110-1301, USA.                                           *
0019  ***************************************************************************/
0020 
0021 #include "PkInstallCatalogs.h"
0022 #include "IntroDialog.h"
0023 #include "FilesModel.h"
0024 
0025 #include <PkStrings.h>
0026 
0027 #include <KLocalizedString>
0028 #include <KMessageBox>
0029 
0030 #include <QLoggingCategory>
0031 
0032 #include <QFile>
0033 
0034 #include <Daemon>
0035 
0036 Q_DECLARE_LOGGING_CATEGORY(APPER_SESSION)
0037 
0038 PkInstallCatalogs::PkInstallCatalogs(uint xid,
0039                                      const QStringList &files,
0040                                      const QString &interaction,
0041                                      const QDBusMessage &message,
0042                                      QWidget *parent)
0043  : SessionTask(xid, interaction, message, parent),
0044    m_interaction(interaction),
0045    m_message(message)
0046 {
0047     setWindowTitle(i18n("Install Packages Catalogs"));
0048 
0049     // Find out how many packages PackageKit is able to resolve
0050     QFile file(QLatin1String("/etc/PackageKit/PackageKit.conf"));
0051     QRegExp rx(QLatin1String("\\s*MaximumItemsToResolve=(\\d+)"), Qt::CaseSensitive);
0052     if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
0053         QTextStream in(&file);
0054         while (!in.atEnd()) {
0055             if (rx.indexIn(in.readLine()) != -1) {
0056                 m_maxResolve = rx.capturedTexts()[1].toInt();
0057                 break;
0058             }
0059         }
0060     }
0061 
0062     const QStringList mimes{
0063         QLatin1String("application/x-catalog"), QLatin1String("text/plain")
0064     };
0065     m_introDialog = new IntroDialog(this);
0066     m_introDialog->acceptDrops(i18n("You can drop more catalogs in here"));
0067     m_model = new FilesModel(files, mimes, this);
0068     connect(m_model, &FilesModel::rowsInserted, this, &PkInstallCatalogs::modelChanged);
0069     m_introDialog->setModel(m_model);
0070     setMainWidget(m_introDialog);
0071 
0072     modelChanged();
0073 }
0074 
0075 PkInstallCatalogs::~PkInstallCatalogs()
0076 {
0077 }
0078 
0079 void PkInstallCatalogs::modelChanged()
0080 {
0081     const QStringList files = m_model->files();
0082     enableButtonOk(!files.isEmpty());
0083     QString description;
0084     if (files.isEmpty()) {
0085         description = i18n("No supported catalog was found");
0086     } else {
0087         description = i18np("Do you want to install this catalog?",
0088                             "Do you want to install these catalogs?",
0089                             files.size());
0090     }
0091     m_introDialog->setDescription(description);
0092 
0093     QString title;
0094     // this will come from DBus interface
0095     if (parentTitle.isNull()) {
0096         title = i18np("An application wants to install a catalog",
0097                       "An application wants to install catalogs",
0098                         files.size());
0099     } else {
0100         title = i18np("The application <i>%2</i> wants to install a catalog",
0101                       "The application <i>%2</i> wants to install catalogs",
0102                         files.size(),
0103                         parentTitle);
0104     }
0105     setTitle(title);
0106 }
0107 
0108 void PkInstallCatalogs::search()
0109 {
0110     const QString distroId = Daemon::global()->distroID();
0111     const QStringList parts = distroId.split(QLatin1Char(';'));
0112     if (parts.size() != 3) {
0113         sendErrorFinished(Failed, QLatin1String("invalid distribution id, please fill a bug against you distribution backend"));
0114         return;
0115     }
0116     const QString distro = parts.at(0);
0117     const QString version = parts.at(1);
0118     const QString arch = parts.at(2);
0119 
0120     QStringList rxActions;
0121     Transaction::Roles roles = Daemon::global()->roles();
0122     if (roles & Transaction::RoleResolve) {
0123         rxActions << QLatin1String("InstallPackages");
0124     }
0125 
0126     if (roles & Transaction::RoleWhatProvides) {
0127         rxActions << QLatin1String("InstallProvides");
0128     }
0129 
0130     if (roles & Transaction::RoleSearchFile) {
0131         rxActions << QLatin1String("InstallFiles");
0132     }
0133 
0134     if (rxActions.isEmpty()) {
0135         if (showWarning()) {
0136             // TODO display a nicer message informing of already installed ones
0137             setInfo(i18n("Not supported"),
0138                     i18n("Your backend does not support any of the needed "
0139                          "methods to install a catalog"));
0140         }
0141         sendErrorFinished(Failed, QLatin1String("not supported by backend"));
0142         return;
0143     }
0144 
0145     // matches at the beginning of line installPackages or InstallProvides or installFiles and capture it
0146     // matches an optional set of parenthesis
0147     // matches *%1* and or *%2* and or *%3*
0148     // matches after '=' but ';' at the end
0149     QString pattern;
0150     pattern = QString(
0151                 QLatin1String("^(%1)(?:\\((?:.*%2[^;]*(?:;(?:.*%3[^;]*(?:;(?:.*%4[^;]*)?)?)?)?)?\\))?=(.*[^;$])"))
0152             .arg(rxActions.join(QLatin1Char('|')), distro, version, arch);
0153     QRegExp rx(pattern, Qt::CaseInsensitive);
0154 
0155     QStringList filesFailedToOpen;
0156     const QStringList files = m_model->files();
0157     if (!files.isEmpty()) {
0158         for (const QString &file : files) {
0159             QFile catalog(file);
0160             if (catalog.open(QIODevice::ReadOnly | QIODevice::Text)) {
0161                 QTextStream in(&catalog);
0162                 while (!in.atEnd()) {
0163                     if (rx.indexIn(in.readLine()) != -1) {
0164                         if (rx.cap(1).compare(QLatin1String("InstallPackages"), Qt::CaseInsensitive) == 0) {
0165                             m_installPackages.append(rx.cap(2).split(QLatin1Char(';')));
0166                         } else if (rx.cap(1).compare(QLatin1String("InstallProvides"), Qt::CaseInsensitive) == 0) {
0167                             m_installProvides.append(rx.cap(2).split(QLatin1Char(';')));
0168                         } else if (rx.cap(1).compare(QLatin1String("InstallFiles"), Qt::CaseInsensitive) == 0) {
0169                             m_installFiles.append(rx.cap(2).split(QLatin1Char(';')));
0170                         }
0171                     }
0172                 }
0173             } else {
0174                 filesFailedToOpen << file;
0175             }
0176         }
0177     } else {
0178         setInfo(i18n("Catalog not found"),
0179                 i18n("Could not find a catalog to install"));
0180         return;
0181     }
0182 
0183     if (showWarning() && filesFailedToOpen.size()) {
0184         // TODO display a nicer message informing of already installed ones
0185         KMessageBox::error(this,
0186                            i18np("Catalog %2 failed to open",
0187                                  "Catalogs %2 failed to open",
0188                                  filesFailedToOpen.size(),
0189                                  filesFailedToOpen.join(QLatin1Char(','))),
0190                            i18n("Failed to open"));
0191     }
0192 
0193     if (m_installPackages.isEmpty() &&
0194         m_installProvides.isEmpty() &&
0195         m_installFiles.isEmpty()) {
0196         setInfo(i18n("Catalog is Empty"),
0197                 i18n("Could not find any package to install in this catalog"));
0198     } else {
0199         // Start resolving
0200         searchFinished(PkTransaction::Success);
0201     }
0202 }
0203 
0204 void PkInstallCatalogs::searchFinished(PkTransaction::ExitStatus status)
0205 {
0206     if (status == PkTransaction::Success) {
0207         if (!m_installPackages.isEmpty()) {
0208             // Continue resolving Install Packages
0209             QStringList resolve;
0210             int count = 0;
0211             while (!m_installPackages.isEmpty() && count < m_maxResolve) {
0212                 // Remove the items from the list so next call we have less
0213                 resolve.append(m_installPackages.takeFirst());
0214                 ++count;
0215             }
0216             qCDebug(APPER_SESSION) << "m_installPackages" << m_maxResolve << m_installPackages.size() << resolve.size();
0217 
0218             auto transaction = new PkTransaction(this);
0219             Transaction *t;
0220             t = Daemon::resolve(resolve,
0221                                 Transaction::FilterNotInstalled | Transaction::FilterArch | Transaction::FilterNewest);
0222             transaction->setupTransaction(t);
0223             setTransaction(Transaction::RoleResolve, transaction);
0224             connect(transaction, &PkTransaction::finished, this, &PkInstallCatalogs::searchFinished, Qt::UniqueConnection);
0225             connect(transaction, &PkTransaction::package, this, &PkInstallCatalogs::addPackage);
0226         } else if (!m_installProvides.isEmpty()) {
0227             // Continue resolving Install Provides
0228             QStringList provides;
0229             int count = 0;
0230             while (!m_installProvides.isEmpty() && count < m_maxResolve) {
0231                 // Remove the items from the list so next call we have less
0232                 provides.append(m_installProvides.takeFirst());
0233                 ++count;
0234             }
0235             qCDebug(APPER_SESSION) << "m_installProvides" <<  m_maxResolve << m_installProvides.size() << provides.size();
0236 
0237             auto transaction = new PkTransaction(this);
0238             Transaction *t;
0239             t = Daemon::whatProvides(provides,
0240                                      Transaction::FilterNotInstalled | Transaction::FilterArch | Transaction::FilterNewest);
0241             transaction->setupTransaction(t);
0242             setTransaction(Transaction::RoleWhatProvides, transaction);
0243             connect(transaction, &PkTransaction::finished, this, &PkInstallCatalogs::searchFinished, Qt::UniqueConnection);
0244             connect(transaction, &PkTransaction::package, this, &PkInstallCatalogs::addPackage);
0245         } else if (!m_installFiles.isEmpty()) {
0246             // Continue resolving Install Packages
0247             QStringList files;
0248             int count = 0;
0249             while (!m_installFiles.isEmpty() && count < m_maxResolve) {
0250                 // Remove the items from the list so next call we have less
0251                 files.append(m_installFiles.takeFirst());
0252                 ++count;
0253             }
0254             qCDebug(APPER_SESSION) << "m_installFiles" << m_maxResolve << m_installFiles.size() << files.size();
0255 
0256             auto transaction = new PkTransaction(this);
0257             Transaction *t;
0258             t = Daemon::searchFiles(files,
0259                                     Transaction::FilterNotInstalled | Transaction::FilterArch | Transaction::FilterNewest);
0260             transaction->setupTransaction(t);
0261             setTransaction(Transaction::RoleSearchFile, transaction);
0262             connect(transaction, &PkTransaction::finished, this, &PkInstallCatalogs::searchFinished, Qt::UniqueConnection);
0263             connect(transaction, &PkTransaction::package, this, &PkInstallCatalogs::addPackage);
0264         } else {
0265             // we are done resolving
0266             SessionTask::searchFinished(status);
0267         }
0268     } else {
0269         // we got an error...
0270         SessionTask::searchFinished(status);
0271     }
0272 }
0273 
0274 #include "moc_PkInstallCatalogs.cpp"