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/Package>
14 #include <KPackage/PackageLoader>
15 #include <KPackage/PackageStructure>
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 {
34 public:
35  Private()
36  {
37  }
38 
39  QString package;
40  QString packageRoot;
41  QString serviceType;
42  Operation operation{UnknownOperation};
43 
44  KPackageTask *runnable{nullptr};
45 };
46 
47 class KPackageTask : public QObject, public QRunnable
48 {
49  Q_OBJECT
50 public:
51  QString package;
52  QString packageRoot;
53  QString serviceType;
54  Operation operation{UnknownOperation};
55 
56  explicit KPackageTask(QObject *parent = nullptr)
57  : QObject(parent)
58  , QRunnable()
59  {
60  // We'll handle our own deletion - otherwise we may end up deleted
61  // before things have been read out that we need to have read
62  // As this has to be set before QThreadPool runs things, we need to do so here
63  setAutoDelete(false);
64  };
65  virtual ~KPackageTask()
66  {
67  }
68  void run() override
69  {
70  qCDebug(KNEWSTUFFCORE) << "Attempting to perform an installation operation of type" << operation << "on the package" << package << "of type"
71  << serviceType << "in the package root" << packageRoot;
72  int errorlevel{0};
73  QString errordescription;
74  // PackageStructure instances are managed internally by KPackage, never delete them
76  if (structure) {
77  qCDebug(KNEWSTUFFCORE) << "Service type understood";
78  installer.reset(new KPackage::Package(structure));
79  if (installer->hasValidStructure()) {
80  qCDebug(KNEWSTUFFCORE) << "Installer successfully created and has a valid structure";
81  switch (operation) {
82  case InstallOperation:
83  job.reset(installer->install(package, packageRoot));
84  break;
85  case UpdateOperation:
86  job.reset(installer->update(package, packageRoot));
87  break;
88  case UninstallOperation:
89  job.reset(installer->uninstall(package, packageRoot));
90  break;
91  case UnknownOperation:
92  default:
93  // This should really not be happening, can't create one of these without going through one
94  // of the functions below, so how'd you get it in this state?
95  break;
96  };
97  if (job) {
98  qCDebug(KNEWSTUFFCORE) << "Created job, now let's wait for it to do its thing...";
99  job->setAutoDelete(false);
100  QEventLoop loop;
101  connect(
102  job.get(),
103  &KJob::result,
104  this,
105  [&loop, &errordescription](KJob *job) { // clazy:exclude=lambda-in-connect
106  errordescription = job->errorText();
107  loop.exit(job->error());
108  },
110  errorlevel = loop.exec();
111  } else {
112  errorlevel = 3;
113  errordescription = i18n(
114  "Failed to create a job for the package management task. This is usually because the package is invalid. We attempted to operate on "
115  "the package %1",
116  package);
117  }
118  } else {
119  errorlevel = 2;
120  errordescription =
121  i18n("Could not create a package installer for the service type %1: The installer does not have a valid structure", serviceType);
122  }
123  } else {
124  errorlevel = 1;
125  errordescription = i18n("The service type %1 was not understood by the KPackage installer", serviceType);
126  }
127  if (errorlevel > 0) {
128  Q_EMIT error(errorlevel, errordescription);
129  }
130  Q_EMIT result();
131  }
132  Q_SIGNAL void result();
133  Q_SIGNAL void error(int errorCode, const QString &errorText);
134 
135 private:
138 };
139 
140 KPackageJob::KPackageJob(QObject *parent)
141  : KJob(parent)
142  , d(new Private)
143 {
144 }
145 
146 KPackageJob::~KPackageJob()
147 {
148  delete d;
149 }
150 
151 void KPackageJob::start()
152 {
153  if (d->runnable) {
154  // refuse to start the task more than once
155  return;
156  }
157  d->runnable = new KPackageTask(this);
158  d->runnable->package = d->package;
159  d->runnable->packageRoot = d->packageRoot;
160  d->runnable->serviceType = d->serviceType;
161  d->runnable->operation = d->operation;
162  connect(
163  d->runnable,
164  &KPackageTask::error,
165  this,
166  [this](int errorCode, const QString &errorText) {
167  setError(errorCode);
168  setErrorText(errorText);
169  },
171  connect(
172  d->runnable,
173  &KPackageTask::result,
174  this,
175  [this]() {
176  emitResult();
177  },
179  QThreadPool::globalInstance()->start(d->runnable);
180 }
181 
182 KNSCore::KPackageJob *KNSCore::KPackageJob::install(const QString &sourcePackage, const QString &packageRoot, const QString &serviceType)
183 {
184  KPackageJob *job = new KPackageJob();
185  job->d->package = sourcePackage;
186  job->d->packageRoot = packageRoot;
187  job->d->serviceType = serviceType;
188  job->d->operation = InstallOperation;
189  QTimer::singleShot(0, job, &KPackageJob::start);
190  return job;
191 }
192 
193 KPackageJob *KPackageJob::update(const QString &sourcePackage, const QString &packageRoot, const QString &serviceType)
194 {
195  KPackageJob *job = new KPackageJob();
196  job->d->package = sourcePackage;
197  job->d->packageRoot = packageRoot;
198  job->d->serviceType = serviceType;
199  job->d->operation = UpdateOperation;
200  QTimer::singleShot(0, job, &KPackageJob::start);
201  return job;
202 }
203 
204 KPackageJob *KPackageJob::uninstall(const QString &packageName, const QString &packageRoot, const QString &serviceType)
205 {
206  KPackageJob *job = new KPackageJob();
207  job->d->package = packageName;
208  job->d->packageRoot = packageRoot;
209  job->d->serviceType = serviceType;
210  job->d->operation = UninstallOperation;
211  QTimer::singleShot(0, job, &KPackageJob::start);
212  return job;
213 }
214 
215 #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 Tue Oct 26 2021 22:43:05 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.