Commit abe43cbe authored by Aleix Pol Gonzalez's avatar Aleix Pol Gonzalez 🐧

flatpak: Port to use FlatpakTransaction

BUG: 395923
parent f2feb345
......@@ -1199,35 +1199,10 @@ Transaction* FlatpakBackend::installApplication(AbstractResource *app, const Add
return nullptr;
}
FlatpakJobTransaction *transaction = nullptr;
FlatpakInstallation *installation = resource->installation();
if (resource->propertyState(FlatpakResource::RequiredRuntime) == FlatpakResource::NotKnownYet && resource->resourceType() == FlatpakResource::DesktopApp) {
transaction = new FlatpakJobTransaction(resource, Transaction::InstallRole, true);
connect(resource, &FlatpakResource::propertyStateChanged, [resource, transaction, this] (FlatpakResource::PropertyKind kind, FlatpakResource::PropertyState state) {
if (kind != FlatpakResource::RequiredRuntime) {
return;
}
if (state == FlatpakResource::AlreadyKnown) {
FlatpakResource *runtime = getRuntimeForApp(resource);
if (runtime && !runtime->isInstalled()) {
transaction->setRuntime(runtime);
}
}
transaction->start();
});
} else {
FlatpakResource *runtime = getRuntimeForApp(resource);
if (runtime && !runtime->isInstalled()) {
transaction = new FlatpakJobTransaction(resource, runtime, Transaction::InstallRole);
} else {
transaction = new FlatpakJobTransaction(resource, Transaction::InstallRole);
}
}
connect(transaction, &FlatpakJobTransaction::statusChanged, [this, installation, resource] (Transaction::Status status) {
FlatpakJobTransaction *transaction = transaction = new FlatpakJobTransaction(resource, Transaction::InstallRole);
connect(transaction, &FlatpakJobTransaction::statusChanged, [this, resource] (Transaction::Status status) {
if (status == Transaction::Status::DoneStatus) {
FlatpakInstallation *installation = resource->installation();
updateAppState(installation, resource);
}
});
......
......@@ -28,7 +28,7 @@ static FlatpakRef * createFakeRef(FlatpakResource *resource)
FlatpakRef *ref = nullptr;
g_autoptr(GError) localError = nullptr;
const QString id = QStringLiteral("%1/%2/%3/%4").arg(resource->typeAsString(), resource->flatpakName(), resource->arch(), resource->branch());
const auto id = resource->ref();
ref = flatpak_ref_parse(id.toUtf8().constData(), &localError);
if (!ref) {
......
......@@ -34,14 +34,8 @@ extern "C" {
}
FlatpakJobTransaction::FlatpakJobTransaction(FlatpakResource *app, Role role, bool delayStart)
: FlatpakJobTransaction(app, nullptr, role, delayStart)
{
}
FlatpakJobTransaction::FlatpakJobTransaction(FlatpakResource *app, FlatpakResource *runtime, Transaction::Role role, bool delayStart)
: Transaction(app->backend(), app, role, {})
, m_app(app)
, m_runtime(runtime)
{
setCancellable(true);
setStatus(QueuedStatus);
......@@ -51,143 +45,29 @@ FlatpakJobTransaction::FlatpakJobTransaction(FlatpakResource *app, FlatpakResour
}
}
FlatpakJobTransaction::~FlatpakJobTransaction()
{
for(auto job : m_jobs) {
if (!job->isFinished()) {
connect(job, &QThread::finished, job, &QObject::deleteLater);
} else
delete job;
}
}
FlatpakJobTransaction::~FlatpakJobTransaction() = default;
void FlatpakJobTransaction::cancel()
{
//note it's possible to have a job cancelled before it ever started as
//sometimes we're delaying the start until we have the runtime
foreach (const QPointer<FlatpakTransactionThread> &job, m_jobs) {
job->cancel();
}
m_appJob->cancel();
setStatus(CancelledStatus);
}
void FlatpakJobTransaction::setRuntime(FlatpakResource *runtime)
{
m_runtime = runtime;
}
void FlatpakJobTransaction::start()
{
setStatus(CommittingStatus);
if (m_runtime) {
QPointer<FlatpakTransactionThread> job = new FlatpakTransactionThread(m_runtime, {}, role());
connect(job, &FlatpakTransactionThread::finished, this, &FlatpakJobTransaction::onJobFinished);
connect(job, &FlatpakTransactionThread::progressChanged, this, &FlatpakJobTransaction::onJobProgressChanged);
m_jobs << job;
processRelatedRefs(m_runtime);
}
// App job will be added everytime
m_appJob = new FlatpakTransactionThread(m_app, {}, role());
connect(m_appJob, &FlatpakTransactionThread::finished, this, &FlatpakJobTransaction::onJobFinished);
m_appJob = new FlatpakTransactionThread(m_app, role());
connect(m_appJob, &FlatpakTransactionThread::finished, this, &FlatpakJobTransaction::finishTransaction);
connect(m_appJob, &FlatpakTransactionThread::progressChanged, this, &FlatpakJobTransaction::onJobProgressChanged);
m_jobs << m_appJob;
processRelatedRefs(m_app);
// Now start all the jobs together
foreach (const QPointer<FlatpakTransactionThread> &job, m_jobs) {
job->start();
}
}
void FlatpakJobTransaction::processRelatedRefs(FlatpakResource* resource)
{
g_autoptr(GPtrArray) refs = nullptr;
g_autoptr(GError) error = nullptr;
g_autoptr(GCancellable) cancellable = g_cancellable_new();;
QList<FlatpakResource> additionalResources;
g_autofree gchar *ref = g_strdup_printf ("%s/%s/%s/%s",
resource->typeAsString().toUtf8().constData(),
resource->flatpakName().toUtf8().constData(),
resource->arch().toUtf8().constData(),
resource->branch().toUtf8().constData());
if (role() == Transaction::Role::InstallRole) {
if (resource->state() == AbstractResource::Upgradeable) {
refs = flatpak_installation_list_installed_related_refs_sync(resource->installation(), resource->origin().toUtf8().constData(), ref, cancellable, &error);
if (error) {
qWarning() << "Failed to list installed related refs for update: " << error->message;
}
} else {
refs = flatpak_installation_list_remote_related_refs_sync(resource->installation(), resource->origin().toUtf8().constData(), ref, cancellable, &error);
if (error) {
qWarning() << "Failed to list related refs for installation: " << error->message;
}
}
} else if (role() == Transaction::Role::RemoveRole) {
refs = flatpak_installation_list_installed_related_refs_sync(resource->installation(), resource->origin().toUtf8().constData(), ref, cancellable, &error);
if (error) {
qWarning() << "Failed to list installed related refs for removal: " << error->message;
}
}
if (refs) {
for (uint i = 0; i < refs->len; i++) {
FlatpakRef *flatpakRef = FLATPAK_REF(g_ptr_array_index(refs, i));
if (flatpak_related_ref_should_download(FLATPAK_RELATED_REF(flatpakRef))) {
QPointer<FlatpakTransactionThread> job = new FlatpakTransactionThread(resource, QPair<QString, uint>(QString::fromUtf8(flatpak_ref_get_name(flatpakRef)), flatpak_ref_get_kind(flatpakRef)), role());
connect(job, &FlatpakTransactionThread::finished, this, &FlatpakJobTransaction::onJobFinished);
connect(job, &FlatpakTransactionThread::progressChanged, this, &FlatpakJobTransaction::onJobProgressChanged);
// Add to the list of all jobs
m_jobs << job;
}
}
}
}
void FlatpakJobTransaction::onJobFinished()
{
FlatpakTransactionThread *job = static_cast<FlatpakTransactionThread*>(sender());
if (job != m_appJob) {
if (!job->result()) {
Q_EMIT passiveMessage(job->errorMessage());
}
// Mark runtime as installed
if (m_runtime && job->app()->flatpakName() == m_runtime->flatpakName() && !job->isRelated() && role() != Transaction::Role::RemoveRole) {
if (job->result()) {
m_runtime->setState(AbstractResource::Installed);
}
}
}
foreach (const QPointer<FlatpakTransactionThread> &job, m_jobs) {
if (job->isRunning()) {
return;
}
}
// No other job is running → finish transaction
finishTransaction();
m_appJob->start();
}
void FlatpakJobTransaction::onJobProgressChanged(int progress)
{
Q_UNUSED(progress);
int total = 0;
// Count progress from all the jobs
foreach (const QPointer<FlatpakTransactionThread> &job, m_jobs) {
total += job->progress();
}
setProgress(total / m_jobs.count());
setProgress(progress);
}
void FlatpakJobTransaction::finishTransaction()
......@@ -208,6 +88,10 @@ void FlatpakJobTransaction::finishTransaction()
setStatus(DoneStatus);
} else {
if (!m_appJob->errorMessage().isEmpty()) {
Q_EMIT passiveMessage(m_appJob->errorMessage());
}
setStatus(DoneWithErrorStatus);
}
}
......@@ -38,27 +38,21 @@ class FlatpakJobTransaction : public Transaction
Q_OBJECT
public:
FlatpakJobTransaction(FlatpakResource *app, Role role, bool delayStart = false);
FlatpakJobTransaction(FlatpakResource *app, FlatpakResource *runtime, Role role, bool delayStart = false);
~FlatpakJobTransaction();
void cancel() override;
void setRuntime(FlatpakResource *runtime);
public Q_SLOTS:
void onJobFinished();
void onJobProgressChanged(int progress);
void finishTransaction();
void start();
private:
void processRelatedRefs(FlatpakResource *resource);
void updateProgress();
QPointer<FlatpakResource> m_app;
QPointer<FlatpakResource> m_runtime;
QPointer<FlatpakTransactionThread> m_appJob;
QList<QPointer<FlatpakTransactionThread> > m_jobs;
};
#endif // FLATPAKJOBTRANSACTION_H
......@@ -145,6 +145,11 @@ void FlatpakResource::updateFromRef(FlatpakRef* ref)
setObjectName(packageName());
}
QString FlatpakResource::ref() const
{
return typeAsString() + QLatin1Char('/') + flatpakName() + QLatin1Char('/') + arch() + QLatin1Char('/') + branch();
}
QStringList FlatpakResource::categories()
{
auto cats = m_appdata.categories();
......
......@@ -59,10 +59,10 @@ public:
};
struct Id {
FlatpakInstallation * installation;
FlatpakInstallation * const installation;
QString origin;
FlatpakResource::ResourceType type;
QString id;
const QString id;
QString branch;
QString arch;
bool operator!=(const Id& other) const { return !operator==(other); }
......@@ -148,6 +148,7 @@ public:
// void setAddonInstalled(const QString& addon, bool installed);
void updateFromRef(FlatpakRef* ref);
QString ref() const;
QString sourceIcon() const override { return QStringLiteral("https://flatpak.org/img/logo.svg"); }
Q_SIGNALS:
......
......@@ -36,20 +36,22 @@ static void flatpakInstallationProgressCallback(const gchar *stats, guint progre
transactionJob->setProgress(progress);
}
FlatpakTransactionThread::FlatpakTransactionThread(FlatpakResource *app, const QPair<QString, uint> &relatedRef, Transaction::Role role)
FlatpakTransactionThread::FlatpakTransactionThread(FlatpakResource *app, Transaction::Role role)
: QThread()
, m_result(false)
, m_progress(0)
, m_relatedRef(relatedRef.first)
, m_relatedRefKind(relatedRef.second)
, m_app(app)
, m_role(role)
{
m_cancellable = g_cancellable_new();
g_autoptr(GError) localError = nullptr;
m_transaction = flatpak_transaction_new_for_installation(m_app->installation(), m_cancellable, &localError);
}
FlatpakTransactionThread::~FlatpakTransactionThread()
{
g_object_unref(m_transaction);
g_object_unref(m_cancellable);
}
......@@ -61,59 +63,34 @@ void FlatpakTransactionThread::cancel()
void FlatpakTransactionThread::run()
{
g_autoptr(GError) localError = nullptr;
g_autoptr(FlatpakInstalledRef) ref = nullptr;
const QString refName = m_relatedRef.isEmpty() ? m_app->flatpakName() : m_relatedRef;
const uint kind = m_relatedRef.isEmpty() ? (uint)m_app->resourceType() : m_relatedRefKind;
const QString refName = m_app->ref();
bool correct = false;
if (m_role == Transaction::Role::InstallRole) {
bool installRelatedRef = false;
// Before we attempt to upgrade related refs we should verify whether they are installed in first place
if (m_app->state() == AbstractResource::Upgradeable && !m_relatedRef.isEmpty()) {
g_autoptr(GError) installedRefError = nullptr;
FlatpakInstalledRef *installedRef = flatpak_installation_get_installed_ref(m_app->installation(),
kind == FlatpakResource::DesktopApp ? FLATPAK_REF_KIND_APP : FLATPAK_REF_KIND_RUNTIME,
refName.toUtf8().constData(),
m_app->arch().toUtf8().constData(),
m_app->branch().toUtf8().constData(),
m_cancellable, &installedRefError);
if (installedRefError) {
qWarning() << "Failed to check whether related ref is installed: " << installedRefError;
}
installRelatedRef = installedRef == nullptr;
}
if (m_app->state() == AbstractResource::Upgradeable && !installRelatedRef) {
ref = flatpak_installation_update(m_app->installation(),
FLATPAK_UPDATE_FLAGS_NONE,
kind == FlatpakResource::DesktopApp ? FLATPAK_REF_KIND_APP : FLATPAK_REF_KIND_RUNTIME,
if (m_app->state() == AbstractResource::Upgradeable && m_app->isInstalled()) {
correct = flatpak_transaction_add_update(m_transaction,
refName.toUtf8().constData(),
m_app->arch().toUtf8().constData(),
m_app->branch().toUtf8().constData(),
flatpakInstallationProgressCallback,
this,
m_cancellable, &localError);
nullptr, nullptr, &localError);
} else {
if (m_app->flatpakFileType() == QStringLiteral("flatpak")) {
g_autoptr(GFile) file = g_file_new_for_path(m_app->resourceFile().toLocalFile().toUtf8().constData());
if (!file) {
qWarning() << "Failed to install bundled application" << refName;
m_result = false;
return;
}
ref = flatpak_installation_install_bundle(m_app->installation(), file, flatpakInstallationProgressCallback, this, m_cancellable, &localError);
correct = flatpak_transaction_add_install_bundle(m_transaction, file, nullptr, &localError);
} else {
ref = flatpak_installation_install(m_app->installation(),
correct = flatpak_transaction_add_install(m_transaction,
m_app->origin().toUtf8().constData(),
kind == FlatpakResource::DesktopApp ? FLATPAK_REF_KIND_APP : FLATPAK_REF_KIND_RUNTIME,
refName.toUtf8().constData(),
m_app->arch().toUtf8().constData(),
m_app->branch().toUtf8().constData(),
flatpakInstallationProgressCallback,
this,
m_cancellable, &localError);
nullptr,
&localError);
}
}
if (!ref) {
if (!correct) {
m_result = false;
m_errorMessage = QString::fromUtf8(localError->message);
// We are done so we can set the progress to 100
......@@ -122,14 +99,9 @@ void FlatpakTransactionThread::run()
return;
}
} else if (m_role == Transaction::Role::RemoveRole) {
if (!flatpak_installation_uninstall(m_app->installation(),
kind == FlatpakResource::DesktopApp ? FLATPAK_REF_KIND_APP : FLATPAK_REF_KIND_RUNTIME,
if (!flatpak_transaction_add_uninstall(m_transaction,
refName.toUtf8().constData(),
m_app->arch().toUtf8().constData(),
m_app->branch().toUtf8().constData(),
flatpakInstallationProgressCallback,
this,
m_cancellable, &localError)) {
&localError)) {
m_result = false;
m_errorMessage = QString::fromUtf8(localError->message);
// We are done so we can set the progress to 100
......@@ -140,7 +112,7 @@ void FlatpakTransactionThread::run()
}
// We are done so we can set the progress to 100
m_result = true;
m_result = flatpak_transaction_run(m_transaction, m_cancellable, &localError);
setProgress(100);
}
......@@ -149,11 +121,6 @@ FlatpakResource * FlatpakTransactionThread::app() const
return m_app;
}
bool FlatpakTransactionThread::isRelated() const
{
return !m_relatedRef.isEmpty();
}
int FlatpakTransactionThread::progress() const
{
return m_progress;
......
......@@ -35,7 +35,7 @@ class FlatpakTransactionThread : public QThread
{
Q_OBJECT
public:
FlatpakTransactionThread(FlatpakResource *app, const QPair<QString, uint> &relatedRef, Transaction::Role role);
FlatpakTransactionThread(FlatpakResource *app, Transaction::Role role);
~FlatpakTransactionThread() override;
void cancel();
......@@ -43,8 +43,6 @@ public:
FlatpakResource * app() const;
bool isRelated() const;
int progress() const;
void setProgress(int progress);
......@@ -55,11 +53,11 @@ Q_SIGNALS:
void progressChanged(int progress);
private:
FlatpakTransaction* m_transaction;
bool m_result;
int m_progress;
QString m_errorMessage;
QString m_relatedRef;
uint m_relatedRefKind;
GCancellable *m_cancellable;
FlatpakResource *m_app;
Transaction::Role m_role;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment