KNewStuff

kpackagejob.cpp
1 /*
2  SPDX-FileCopyrightText: 2020 Dan Leinir Turthra Jensen <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6 
7 #include "kpackagejob.h"
8 
9 #include <knewstuffcore_debug.h>
10 
11 #include <KLocalizedString>
12 
13 #include <KPackage/PackageStructure>
14 #include <KPackage/Package>
15 #include <KPackage/PackageLoader>
16 
17 #include <QCoreApplication>
18 #include <QRunnable>
19 #include <QStandardPaths>
20 #include <QThreadPool>
21 #include <QTimer>
22 
23 using namespace KNSCore;
24 
25 enum Operation {
26  UnknownOperation,
27  InstallOperation,
28  UpdateOperation,
29  UninstallOperation,
30 };
31 class KPackageTask;
32 class KPackageJob::Private {
33 public:
34  Private() {}
35 
36  QString package;
37  QString packageRoot;
38  QString serviceType;
39  Operation operation{UnknownOperation};
40 
41  KPackageTask* runnable{nullptr};
42 };
43 
44 class KPackageTask : public QObject, public QRunnable
45 {
46  Q_OBJECT
47 public:
48  QString package;
49  QString packageRoot;
50  QString serviceType;
51  Operation operation{UnknownOperation};
52 
53  explicit KPackageTask(QObject* parent = nullptr)
54  : QObject(parent)
55  , QRunnable()
56  {
57  // We'll handle our own deletion - otherwise we may end up deleted
58  // before things have been read out that we need to have read
59  // As this has to be set before QThreadPool runs things, we need to do so here
60  setAutoDelete(false);
61  };
62  virtual ~KPackageTask() {}
63  void run() override
64  {
65  qCDebug(KNEWSTUFFCORE) << "Attempting to perform an installation operation of type" << operation << "on the package" << package << "of type" << serviceType << "in the package root" << packageRoot;
66  int errorlevel{0};
67  QString errordescription;
68  // PackageStructure instances are managed internally by KPackage, never delete them
70  if (structure) {
71  qCDebug(KNEWSTUFFCORE) << "Service type understood";
72  installer.reset(new KPackage::Package(structure));
73  if (installer->hasValidStructure()) {
74  qCDebug(KNEWSTUFFCORE) << "Installer successfully created and has a valid structure";
75  switch(operation)
76  {
77  case InstallOperation:
78  job.reset(installer->install(package, packageRoot));
79  break;
80  case UpdateOperation:
81  job.reset(installer->update(package, packageRoot));
82  break;
83  case UninstallOperation:
84  job.reset(installer->uninstall(package, packageRoot));
85  break;
86  case UnknownOperation:
87  default:
88  // This should really not be happening, can't create one of these without going through one
89  // of the functions below, so how'd you get it in this state?
90  break;
91  };
92  if (job) {
93  qCDebug(KNEWSTUFFCORE) << "Created job, now let's wait for it to do its thing...";
94  job->setAutoDelete(false);
95  QEventLoop loop;
96  connect(job.get(), &KJob::result, this, [&loop,&errordescription](KJob* job){
97  errordescription = job->errorText();
98  loop.exit(job->error());
100  errorlevel = loop.exec();
101  } else {
102  errorlevel = 3;
103  errordescription = i18n("Failed to create a job for the package management task. This is usually because the package is invalid. We attempted to operate on the package %1", package);
104  }
105  } else {
106  errorlevel = 2;
107  errordescription = i18n("Could not create a package installer for the service type %1: The installer does not have a valid structure", serviceType);
108  }
109  } else {
110  errorlevel = 1;
111  errordescription = i18n("The service type %1 was not understood by the KPackage installer", serviceType);
112  }
113  if (errorlevel > 0) {
114  Q_EMIT error(errorlevel, errordescription);
115  }
116  Q_EMIT result();
117  }
118  Q_SIGNAL void result();
119  Q_SIGNAL void error(int errorCode, const QString& errorText);
120 private:
123 };
124 
125 KPackageJob::KPackageJob(QObject* parent)
126  : KJob(parent)
127  , d(new Private)
128 {
129 }
130 
131 KPackageJob::~KPackageJob()
132 {
133  delete d;
134 }
135 
136 void KPackageJob::start()
137 {
138  if (d->runnable) {
139  // refuse to start the task more than once
140  return;
141  }
142  d->runnable = new KPackageTask(this);
143  d->runnable->package = d->package;
144  d->runnable->packageRoot = d->packageRoot;
145  d->runnable->serviceType = d->serviceType;
146  d->runnable->operation = d->operation;
147  connect(d->runnable, &KPackageTask::error, this, [this](int errorCode, const QString& errorText){
148  setError(errorCode);
149  setErrorText(errorText);
151  connect(d->runnable, &KPackageTask::result, this, [this](){ emitResult(); }, Qt::QueuedConnection);
152  QThreadPool::globalInstance()->start(d->runnable);
153 }
154 
155 KNSCore::KPackageJob * KNSCore::KPackageJob::install(const QString &sourcePackage, const QString &packageRoot, const QString &serviceType)
156 {
157  KPackageJob* job = new KPackageJob();
158  job->d->package = sourcePackage;
159  job->d->packageRoot = packageRoot;
160  job->d->serviceType = serviceType;
161  job->d->operation = InstallOperation;
162  QTimer::singleShot(0, job, &KPackageJob::start);
163  return job;
164 }
165 
166 KPackageJob * KPackageJob::update(const QString &sourcePackage, const QString &packageRoot, const QString &serviceType)
167 {
168  KPackageJob* job = new KPackageJob();
169  job->d->package = sourcePackage;
170  job->d->packageRoot = packageRoot;
171  job->d->serviceType = serviceType;
172  job->d->operation = UpdateOperation;
173  QTimer::singleShot(0, job, &KPackageJob::start);
174  return job;
175 }
176 
177 KPackageJob * KPackageJob::uninstall(const QString &packageName, const QString &packageRoot, const QString &serviceType)
178 {
179  KPackageJob* job = new KPackageJob();
180  job->d->package = packageName;
181  job->d->packageRoot = packageRoot;
182  job->d->serviceType = serviceType;
183  job->d->operation = UninstallOperation;
184  QTimer::singleShot(0, job, &KPackageJob::start);
185  return job;
186 }
187 
188 #include "kpackagejob.moc"
QThreadPool * globalInstance()
Contains the core functionality for handling interaction with NewStuff providers. ...
static PackageLoader * self()
A job for performing basic actions on KPackage packages asynchronously.
Definition: kpackagejob.h:23
Q_OBJECTQ_OBJECT
KPackage::PackageStructure * loadPackageStructure(const QString &packageFormat)
QString i18n(const char *text, const TYPE &arg...)
Q_SIGNALQ_SIGNAL
static KPackageJob * install(const QString &sourcePackage, const QString &packageRoot, const QString &serviceType)
Create a job for installing the given package into the package root, and treat it as the given servic...
KIOWIDGETS_EXPORT bool run(const QUrl &_url, bool _is_local)
void result(KJob *job)
void start(QRunnable *runnable, int priority)
BlockingQueuedConnection
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setAutoDelete(bool autodelete)
QObject * parent() const const
Q_EMITQ_EMIT
QString errorText() const
int error() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Jan 18 2021 22:43:50 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.