A bunch of improvements
This commit is contained in:
parent
29c1eb8abb
commit
1ccbb8b1a0
@ -32,6 +32,8 @@ set(PROJECT_SOURCES
|
||||
conffilehandlerdialog.h
|
||||
conffilehandlerdialog.cpp
|
||||
conffilehandlerdialog.ui
|
||||
ipcfilewatcher.h
|
||||
ipcfilewatcher.cpp
|
||||
${TS_FILES}
|
||||
)
|
||||
|
||||
@ -60,6 +62,18 @@ install(TARGETS lubuntu-update
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
# Yes, we are hardcoding a path here. Yes, it's ugly. However, the program
|
||||
# will attempt to run this script as root, and I do NOT want to make it try to
|
||||
# "find" the script and execute the first thing it finds that has the right
|
||||
# name, that sounds like a security breach waiting to happen. It will only
|
||||
# execute lubuntu-update-backend from /usr/libexec, and if something malicious
|
||||
# has gotten into /usr/libexec you're compromised anyway, so not much to worry
|
||||
# about. Therefore we always, *always* install this script into /usr/libexec/,
|
||||
# no matter where the rest of the program goes.
|
||||
install(FILES lubuntu-update-backend DESTINATION /usr/libexec/)
|
||||
|
||||
install(FILES lubuntu-update.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications/)
|
||||
|
||||
if(QT_VERSION_MAJOR EQUAL 6)
|
||||
qt_finalize_executable(lubuntu-update)
|
||||
endif()
|
||||
|
10
README.md
10
README.md
@ -14,8 +14,16 @@ cmake ..
|
||||
make -j$(nproc)
|
||||
```
|
||||
|
||||
To use, copy the lubuntu-update-backend script to /usr/bin/lubuntu-update-backend, then compile and run the updater. It is highly recommended that you **do not** install the updater all the way into your system with `sudo make install` or similar.
|
||||
To use, copy the lubuntu-update-backend script to /usr/libexec/lubuntu-update-backend, then compile and run the updater. It is highly recommended that you **do not** install the updater all the way into your system with `sudo make install` or similar.
|
||||
|
||||
It is highly recommended that you use a Lubuntu virtual machine for testing and development. Use the latest development release if at all possible, unless you know you need to test an earlier release.
|
||||
|
||||
Qt Creator is recommended for editing the code. It is present in Ubuntu's official repos and can be installed using `sudo apt install qtcreator`.
|
||||
|
||||
## Missing features
|
||||
|
||||
* The Details button is hidden and does nothing. Eventually it should display a list of packages, the old version of them, the new version of them, and a link to their Launchpad page.
|
||||
* There's no support for release upgrading. This is currently unnecessary as this updater is only going to be shipped in Noble and later, but it will become a big deal in the (potentially near) future.
|
||||
* There's no support for doing an `apt update` for checking for recent updates. This seems rather important *now*.
|
||||
* Most of the internal strings aren't translatable...
|
||||
* ...and the bit of translation support there is, is totally untested and quite possibly not functioning properly. Borrow from what we did with lubuntu-installer-prompt to fix this.
|
||||
|
@ -28,7 +28,7 @@ void AptManager::applyFullUpgrade()
|
||||
aptProcess = new QProcess();
|
||||
aptProcess->setProgram("/usr/bin/lxqt-sudo");
|
||||
// Note that the lubuntu-update-backend script sets LC_ALL=C in it already, so we don't need to add that here.
|
||||
aptProcess->setArguments(QStringList() << "/usr/bin/lubuntu-update-backend" << "doupdate");
|
||||
aptProcess->setArguments(QStringList() << "/usr/libexec/lubuntu-update-backend" << "doupdate");
|
||||
aptProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||
QObject::connect(aptProcess, &QProcess::readyRead, this, &AptManager::handleProcessBuffer);
|
||||
QObject::connect(aptProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &AptManager::handleProcessBuffer);
|
||||
|
38
ipcfilewatcher.cpp
Normal file
38
ipcfilewatcher.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include "ipcfilewatcher.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileSystemWatcher>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
IPCFileWatcher::IPCFileWatcher(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
QDir targetDir("/dev/shm/lubuntu-update");
|
||||
bool couldRemove = targetDir.removeRecursively();
|
||||
if (!couldRemove) {
|
||||
qCritical() << "Could not clear IPC directory. Ensure that /dev/shm and /dev/shm/lubuntu-update are world-readable and world-writable.";
|
||||
initFailed = true;
|
||||
return;
|
||||
}
|
||||
targetDir.mkdir("/dev/shm/lubuntu-update");
|
||||
QFileSystemWatcher *watcher = new QFileSystemWatcher(QStringList() << "/dev/shm/lubuntu-update");
|
||||
connect(watcher, &QFileSystemWatcher::directoryChanged, this, &IPCFileWatcher::checkForShowWindowFile);
|
||||
initFailed = false;
|
||||
}
|
||||
|
||||
bool IPCFileWatcher::didInitFail()
|
||||
{
|
||||
return initFailed;
|
||||
}
|
||||
|
||||
void IPCFileWatcher::checkForShowWindowFile()
|
||||
{
|
||||
QFile flagFile("/dev/shm/lubuntu-update/lubuntu-update-show-win");
|
||||
if (flagFile.exists()) {
|
||||
flagFile.remove();
|
||||
emit showWindowFlagDetected();
|
||||
}
|
||||
}
|
22
ipcfilewatcher.h
Normal file
22
ipcfilewatcher.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef IPCFILEWATCHER_H
|
||||
#define IPCFILEWATCHER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class IPCFileWatcher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IPCFileWatcher(QObject *parent = nullptr);
|
||||
bool didInitFail();
|
||||
|
||||
signals:
|
||||
void showWindowFlagDetected();
|
||||
|
||||
private:
|
||||
bool initFailed;
|
||||
|
||||
void checkForShowWindowFile();
|
||||
};
|
||||
|
||||
#endif // IPCFILEWATCHER_H
|
11
lubuntu-update.desktop
Normal file
11
lubuntu-update.desktop
Normal file
@ -0,0 +1,11 @@
|
||||
[Desktop Entry]
|
||||
Exec=/usr/bin/lubuntu-update
|
||||
Name=Lubuntu Update
|
||||
GenericName=Lubuntu Update
|
||||
Comment=View available updates and optionally install them
|
||||
Icon=system-software-update
|
||||
Type=Application
|
||||
Version=0.1
|
||||
Categories=System;Settings;
|
||||
Keywords=upgrade;update
|
||||
Terminal=false
|
39
main.cpp
39
main.cpp
@ -1,3 +1,4 @@
|
||||
#include "ipcfilewatcher.h"
|
||||
#include "orchestrator.h"
|
||||
#include "mainwindow.h"
|
||||
#include "conffilehandlerdialog.h"
|
||||
@ -5,6 +6,7 @@
|
||||
#include <QApplication>
|
||||
#include <QDialog>
|
||||
#include <QLocale>
|
||||
#include <QProcess>
|
||||
#include <QTranslator>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -20,9 +22,44 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If Lubuntu Update is already running, create
|
||||
* /dev/shm/lubuntu-update/lubuntu-update-show-win and exit. This will
|
||||
* trigger the existing process to pop up a window.
|
||||
*/
|
||||
|
||||
QProcess procDetector;
|
||||
procDetector.setProgram("/usr/bin/bash");
|
||||
procDetector.setArguments(QStringList() << "-c" << "ps axo comm | grep lubuntu-update");
|
||||
procDetector.start();
|
||||
procDetector.waitForFinished();
|
||||
QString procDetectResult = procDetector.readAllStandardOutput();
|
||||
procDetectResult = procDetectResult.trimmed();
|
||||
QStringList procDetectResultList = procDetectResult.split('\n');
|
||||
if (procDetectResultList.count() > 1) {
|
||||
QFile flagFile("/dev/shm/lubuntu-update/lubuntu-update-show-win");
|
||||
flagFile.open(QFile::WriteOnly);
|
||||
flagFile.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Don't want the updater to stop just because the user closed it :P
|
||||
a.setQuitOnLastWindowClosed(false);
|
||||
|
||||
/*
|
||||
* IPCFileWatcher just watches the /dev/shm/lubuntu-update folder for the
|
||||
* creation of a lubuntu-update-show-win file. If it detects it, it
|
||||
* immediately deletes it and emits a signal. This is then used later to
|
||||
* cause the updater window to pop up.
|
||||
*/
|
||||
|
||||
IPCFileWatcher *p = new IPCFileWatcher();
|
||||
|
||||
if (p->didInitFail()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* As this is a background process, we don't pop up any window upon
|
||||
* startup. An Orchestrator object periodically checks to see if new
|
||||
@ -37,6 +74,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
Orchestrator *o = new Orchestrator();
|
||||
|
||||
QObject::connect(p, &IPCFileWatcher::showWindowFlagDetected, o, &Orchestrator::displayUpdater);
|
||||
|
||||
/*
|
||||
* This is an artifact from testing the conffile handler window. You can
|
||||
* uncomment this and rebuild lubuntu-update in order to test the conffile
|
||||
|
@ -17,6 +17,9 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
ui->progressBar->setVisible(false);
|
||||
ui->logView->setVisible(false);
|
||||
|
||||
// FIXME: Implement the Details screen and attach this button to it rather than disabling it.
|
||||
ui->detailsButton->setVisible(false);
|
||||
|
||||
connect(ui->installButton, &QPushButton::clicked, this, &MainWindow::onInstallButtonClicked);
|
||||
connect(ui->closeButton, &QPushButton::clicked, this, &MainWindow::onCloseButtonClicked);
|
||||
connect(aptManager, &AptManager::updateComplete, this, &MainWindow::onUpdateCompleted);
|
||||
@ -36,11 +39,15 @@ void MainWindow::setUpdateInfo(QList<QStringList> updateInfo)
|
||||
// The progress bar and log view are shown after the user chooses to begin installing updates
|
||||
ui->progressBar->setVisible(false);
|
||||
ui->logView->setVisible(false);
|
||||
ui->installButton->setEnabled(true);
|
||||
ui->detailsButton->setEnabled(true);
|
||||
ui->closeButton->setEnabled(true);
|
||||
ui->installButton->setEnabled(false); // Correct, it starts out false, we turn it to true if there are any updates.
|
||||
|
||||
for (int i = 0;i < 4;i++) {
|
||||
if (updateInfo[i].count() > 0) {
|
||||
ui->installButton->setEnabled(true);
|
||||
}
|
||||
|
||||
QTreeWidgetItem *installItem;
|
||||
switch (i) {
|
||||
case 0:
|
||||
@ -69,6 +76,18 @@ void MainWindow::setUpdateInfo(QList<QStringList> updateInfo)
|
||||
QString::number(updateInfo[4].count())));
|
||||
}
|
||||
|
||||
bool MainWindow::isLockedOpen()
|
||||
{
|
||||
/*
|
||||
* If the Close button is disabled, we do NOT want the window to close
|
||||
* under virtually any circumstances. This allows the Orchestrator to
|
||||
* determine whether or not it is save to close and re-open the window
|
||||
* from the outside.
|
||||
*/
|
||||
|
||||
return !ui->closeButton->isEnabled();
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
/*
|
||||
@ -99,6 +118,7 @@ void MainWindow::onCloseButtonClicked()
|
||||
void MainWindow::onUpdateCompleted()
|
||||
{
|
||||
ui->closeButton->setEnabled(true);
|
||||
ui->installButton->setEnabled(false);
|
||||
ui->progressBar->setVisible(false);
|
||||
ui->statLabel->setText("Update installation complete.");
|
||||
emit updatesInstalled(); // this tells the orchestrator to hide the tray icon
|
||||
|
@ -21,6 +21,7 @@ public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
void setUpdateInfo(QList<QStringList> updateInfo);
|
||||
bool isLockedOpen();
|
||||
|
||||
signals:
|
||||
void updatesInstalled();
|
||||
|
@ -13,7 +13,7 @@ Orchestrator::Orchestrator(QObject *parent)
|
||||
trayIcon = new QSystemTrayIcon(); // this is shown to the user to offer updates
|
||||
|
||||
connect(checkTimer, &QTimer::timeout, this, &Orchestrator::checkForUpdates);
|
||||
connect(trayIcon, &QSystemTrayIcon::activated, this, [this](){this->displayUpdater(updateInfo);});
|
||||
connect(trayIcon, &QSystemTrayIcon::activated, this, &Orchestrator::displayUpdater);
|
||||
connect(&updaterWindow, &MainWindow::updatesInstalled, this, &Orchestrator::handleUpdatesInstalled);
|
||||
|
||||
checkTimer->start(21600000); // check four times a day, at least one of those times unattended-upgrades should have refreshed the apt database
|
||||
@ -39,9 +39,12 @@ void Orchestrator::checkForUpdates()
|
||||
}
|
||||
}
|
||||
|
||||
void Orchestrator::displayUpdater(QList<QStringList> updateInfo)
|
||||
void Orchestrator::displayUpdater()
|
||||
{
|
||||
if (!updaterWindow.isVisible()) {
|
||||
if (!updaterWindow.isLockedOpen()) {
|
||||
if (!updaterWindow.isVisible()) {
|
||||
updaterWindow.hide();
|
||||
}
|
||||
updaterWindow.setUpdateInfo(updateInfo);
|
||||
updaterWindow.show();
|
||||
}
|
||||
@ -49,5 +52,9 @@ void Orchestrator::displayUpdater(QList<QStringList> updateInfo)
|
||||
|
||||
void Orchestrator::handleUpdatesInstalled()
|
||||
{
|
||||
// We can't clear the updateInfo list directly as MainWindow::setUpdateInfo requires that it contains five inner lists (even if those lists are all empty).
|
||||
for (int i = 0;i < 5;i++) {
|
||||
updateInfo[i].clear();
|
||||
}
|
||||
trayIcon->hide();
|
||||
}
|
||||
|
@ -15,9 +15,11 @@ class Orchestrator : public QObject
|
||||
public:
|
||||
explicit Orchestrator(QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void displayUpdater();
|
||||
|
||||
private slots:
|
||||
void checkForUpdates();
|
||||
void displayUpdater(QList<QStringList> updateInfo);
|
||||
void handleUpdatesInstalled();
|
||||
|
||||
private:
|
||||
|
Loading…
x
Reference in New Issue
Block a user