Skip to content

Commit 7adbf26

Browse files
committed
improve error detection and displaying for system update
1 parent 4f47cc4 commit 7adbf26

File tree

3 files changed

+106
-23
lines changed

3 files changed

+106
-23
lines changed

src/resources/qml/SystemUpdate.qml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,39 @@ Kirigami.Page {
6464
i18n("Open console") + Gamepad.labels.space + Gamepad.labels.y,
6565
function() {consoleDrawer.drawerOpen = true;}
6666
);
67+
}, function(errorJson) {
68+
// This function is only called if part of the update has failed
69+
try {
70+
let errors = JSON.parse(errorJson);
71+
let message = i18n("Some update modules failed:\n");
72+
73+
if (errors.System_Update) {
74+
message += i18n("System Update\n");
75+
}
76+
if (errors.Brew_Update) {
77+
message += i18n("Brew Update\n");
78+
}
79+
if (errors.System_Apps) {
80+
message += i18n("System Flatpak Apps\n");
81+
}
82+
if (errors.Apps_for_User) {
83+
message += i18n("User Flatpak Apps\n");
84+
}
85+
if (errors.Distroboxes_for_User) {
86+
message += i18n("User Distroboxes\n");
87+
}
88+
if (errors.Unknown_Error) {
89+
message += i18n("Unknown (Please send the error logs!)\n");
90+
}
91+
92+
if (message.endsWith("\n")) {
93+
message = message.slice(0, -1);
94+
}
95+
showPassiveNotification(message, Kirigami.long);
96+
97+
} catch (e) {
98+
console.error("Failed to parse error JSON:", e);
99+
}
67100
});
68101
}
69102
}

src/system_update.cpp

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <QProcess>
1515
#include <QStandardPaths>
1616
#include <QTextStream>
17+
#include <QTimer>
1718

1819
#include <KLocalizedString>
1920

@@ -31,7 +32,7 @@ SystemUpdate::SystemUpdate(QObject *parent)
3132
{
3233
}
3334

34-
void SystemUpdate::runUpdate(QJSValue callback)
35+
void SystemUpdate::runUpdate(QJSValue callback, QJSValue callbackErrors)
3536
{
3637
if (!callback.isCallable()) {
3738
qDebug() << "Callback is not callable, command run refused";
@@ -56,28 +57,51 @@ void SystemUpdate::runUpdate(QJSValue callback)
5657

5758
// When the "systemctl start uupd-manual.service" process completes,
5859
// check the service result and update the UI accordingly.
60+
// NOTE: A race condition can likely occur between this and the process in logToConsole()
5961
connect(systemctl, &QProcess::finished, [=]() {
60-
const QString result = getServiceResult(u"uupd-manual.service"_s);
61-
if (result == u"success"_s) {
62+
QTimer::singleShot(500, this, [=]() {
63+
if (m_updateErrorStatus.System_Update || m_updateErrorStatus.Brew_Update || m_updateErrorStatus.System_Apps || m_updateErrorStatus.Apps_for_User
64+
|| m_updateErrorStatus.Distroboxes_for_User || m_updateErrorStatus.Unknown_Error) {
65+
// Used in QML to send notification of which part(s) of the update failed
66+
67+
QJsonObject errorDetails;
68+
errorDetails[u"System_Update"_s] = m_updateErrorStatus.System_Update;
69+
errorDetails[u"Brew_Update"_s] = m_updateErrorStatus.Brew_Update;
70+
errorDetails[u"System_Apps"_s] = m_updateErrorStatus.System_Apps;
71+
errorDetails[u"Apps_for_User"_s] = m_updateErrorStatus.Apps_for_User;
72+
errorDetails[u"Distroboxes_for_User"_s] = m_updateErrorStatus.Distroboxes_for_User;
73+
errorDetails[u"Unknown_Error"_s] = m_updateErrorStatus.Unknown_Error;
74+
75+
QJsonDocument errorDoc(errorDetails);
76+
QString errorJson = QString::fromUtf8(errorDoc.toJson(QJsonDocument::Compact));
77+
78+
if (callbackErrors.isCallable()) {
79+
callbackErrors.call({errorJson});
80+
}
81+
}
82+
83+
const QString result = getServiceResult(u"uupd-manual.service"_s);
84+
if (result == u"success"_s) {
85+
m_appState->setUpdateRunning(false);
86+
m_appState->setCommandSucceeded(true);
87+
88+
setStatusText(i18n("Complete"));
89+
callback.call({0, result});
90+
systemctl->deleteLater();
91+
return;
92+
} else if (result == u"start-limit-hit"_s) {
93+
setStatusText(i18n("Updating too fast! ") + result);
94+
appendConsoleText(i18n("You are updating too many times in a short period!"), LogLevel::ERROR);
95+
} else {
96+
setStatusText(i18n("Error: ") + result);
97+
qDebug() << "Result of uupd-manual.service was not success: " << result;
98+
}
6299
m_appState->setUpdateRunning(false);
63-
m_appState->setCommandSucceeded(true);
100+
callback.call({1, result});
64101

65-
setStatusText(i18n("Success!"));
66-
callback.call({0, result});
67102
systemctl->deleteLater();
68103
return;
69-
} else if (result == u"start-limit-hit"_s) {
70-
setStatusText(i18n("Updating too fast! ") + result);
71-
appendConsoleText(i18n("You are updating too many times in a short period!"), LogLevel::ERROR);
72-
} else {
73-
setStatusText(i18n("Error: ") + result);
74-
qDebug() << "Result of uupd-manual.service was not success: " << result;
75-
}
76-
m_appState->setUpdateRunning(false);
77-
callback.call({1, result});
78-
79-
systemctl->deleteLater();
80-
return;
104+
});
81105
});
82106
}
83107

@@ -138,12 +162,21 @@ void SystemUpdate::logToConsole()
138162
QString context = output.value(u"Context"_s).toString();
139163
msg = i18n("Module Failed: ") + context;
140164

141-
// TODO: make sure one of these is correct
142-
if (context.contains(u"system"_s, Qt::CaseInsensitive) || context.contains(u"ostree"_s, Qt::CaseInsensitive)
143-
|| context.contains(u"bootc"_s, Qt::CaseInsensitive)) {
165+
if (context.contains(u"System Update"_s, Qt::CaseInsensitive)) {
144166
setBlockUpdate(true);
145167
log_level = LogLevel::ERROR_CRITICAL;
146168
setStatusText(i18n(("CRITICAL ERROR!")));
169+
m_updateErrorStatus.System_Update = true;
170+
} else if (context.contains(u"Brew Update"_s, Qt::CaseInsensitive)) {
171+
m_updateErrorStatus.Brew_Update = true;
172+
} else if (context.contains(u"System Apps"_s, Qt::CaseInsensitive)) {
173+
m_updateErrorStatus.System_Apps = true;
174+
} else if (context.contains(u"Apps for User"_s, Qt::CaseInsensitive)) {
175+
m_updateErrorStatus.Apps_for_User = true;
176+
} else if (context.contains(u"Distroboxes for User"_s, Qt::CaseInsensitive)) {
177+
m_updateErrorStatus.Distroboxes_for_User = true;
178+
} else {
179+
m_updateErrorStatus.Unknown_Error = true;
147180
}
148181
}
149182
}
@@ -187,7 +220,13 @@ QString SystemUpdate::getServiceResult(const QString &service) const
187220

188221
void SystemUpdate::copyToClipboard(const QString &content) const
189222
{
190-
QApplication::clipboard()->setText(content);
223+
// Remove HTML tags
224+
static QRegularExpression htmlTagPattern(QStringLiteral(R"(<[^>]*>)"));
225+
QString plainText = content;
226+
plainText.replace(u"<br>"_s, u"\n"_s);
227+
plainText.replace(htmlTagPattern, u""_s);
228+
229+
QApplication::clipboard()->setText(plainText);
191230
}
192231

193232
void SystemUpdate::setConsoleText(const QString &consoleText)

src/system_update.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ class SystemUpdate : public QObject
4545
bool m_blockUpdate = false;
4646
QProcess m_journalctlProcess;
4747

48+
struct UpdateErrors {
49+
bool System_Update = false;
50+
bool Brew_Update = false;
51+
bool System_Apps = false;
52+
bool Apps_for_User = false;
53+
bool Distroboxes_for_User = false;
54+
bool Unknown_Error = false;
55+
};
56+
57+
UpdateErrors m_updateErrorStatus;
58+
4859
QString getServiceState(const QString &service) const;
4960
QString getServiceResult(const QString &service) const;
5061
void logToConsole();
@@ -63,7 +74,7 @@ class SystemUpdate : public QObject
6374
public:
6475
SystemUpdate(QObject *parent = nullptr);
6576

66-
Q_INVOKABLE void runUpdate(QJSValue callback = QJSValue());
77+
Q_INVOKABLE void runUpdate(QJSValue callback = QJSValue(), QJSValue callbackErrors = QJSValue());
6778

6879
Q_INVOKABLE void copyToClipboard(const QString &content) const;
6980

0 commit comments

Comments
 (0)