完善了APT包管理器后端的功能,基本实现安装

This commit is contained in:
RigoLigoRLC 2022-02-15 23:36:04 +08:00
parent ae987f9542
commit ed233e2625
12 changed files with 288 additions and 140 deletions

@ -19,6 +19,9 @@ namespace SpkUi
mMainArea->setWidget(mSettingsWidget);
mMainArea->setWidgetResizable(true);
CFG->BindField("url/repo", &this->mRepoListUrl,
"https://d.store.deepinos.org.cn/store/server.list");
SetupUi();
}
@ -50,20 +53,21 @@ namespace SpkUi
ui->edtDownloadPath->setText(CFG->ReadField("dirs/download", "").toString());
ui->edtDownloadServers->setPlainText(CFG->ReadField("download/servers", "").toString());
ui->edtQssPath->setText(CFG->ReadField("internal/qss_path", "").toString());
ui->edtRepoListUrl->setText(CFG->ReadField("url/repo", "").toString());
}
void SpkPageSettings::SaveConfiguration()
{
auto ui = mSettingsUi;
auto settings = CFG;
CFG->SetSettings("resource/concurrent", ui->spnConcurrentResDownloads->value());
assert(CFG->SetField("url/api", ui->edtApiUrl->text()));
assert(CFG->SetField("url/res", ui->edtResourceUrl->text()));
CFG->SetField("url/api", ui->edtApiUrl->text());
CFG->SetField("url/res", ui->edtResourceUrl->text());
CFG->SetSettings("dirs/cache", ui->edtResourceCachePath->text());
assert(CFG->SetField("dirs/download", ui->edtDownloadPath->text()));
assert(CFG->SetField("download/servers", ui->edtDownloadServers->toPlainText()));
CFG->SetField("dirs/download", ui->edtDownloadPath->text());
CFG->SetField("download/servers", ui->edtDownloadServers->toPlainText());
CFG->SetSettings("internal/qss_path", ui->edtQssPath->text());
CFG->SetField("url/repo", ui->edtRepoListUrl->text());
}
void SpkPageSettings::Activated()

@ -83,7 +83,7 @@ SpkUi::SpkPageUiTest::SpkPageUiTest(QWidget *parent) : QSplitter(parent)
ShowPkgmgr = new QPushButton(this);
ShowPkgmgr->setText("Show Install Menu");
connect(ShowPkgmgr, &QPushButton::clicked, [](){ SpkPkgMgrBase::Instance()->ExecuteInstallation("", 0); });
connect(ShowPkgmgr, &QPushButton::clicked, [=](){ SpkPkgMgrBase::Instance()->ExecuteInstallation(PopupText->text(), 0); });
SlideV = new QSlider(this);
SlideV->setObjectName("spk_pg_qsstest_slider_v");

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>501</width>
<height>699</height>
<width>581</width>
<height>896</height>
</rect>
</property>
<property name="windowTitle">
@ -61,41 +61,17 @@
</item>
<item>
<layout class="QGridLayout" name="laySettings">
<item row="3" column="1">
<widget class="QPlainTextEdit" name="edtDownloadServers">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>80</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>150</height>
</size>
</property>
<property name="baseSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="spkcfg_key" stdset="0">
<string notr="true">download/servers</string>
<item row="5" column="0">
<widget class="QLabel" name="lblApiUrl">
<property name="text">
<string>Store API URL</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblLightDarkTheme">
<item row="6" column="0">
<widget class="QLabel" name="lblResourceUrl">
<property name="text">
<string>Light/dark theme</string>
<string>Store resource URL</string>
</property>
</widget>
</item>
@ -106,75 +82,6 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cmbLightDarkTheme">
<property name="frame">
<bool>true</bool>
</property>
<property name="spkcfg_key" stdset="0">
<string notr="true">gui/theme</string>
</property>
<item>
<property name="text">
<string>Auto</string>
</property>
</item>
<item>
<property name="text">
<string>Always Light</string>
</property>
</item>
<item>
<property name="text">
<string>Always Dark</string>
</property>
</item>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="lblApiUrl">
<property name="text">
<string>Store API URL</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblAptRepo">
<property name="text">
<string>APT Repository</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="edtApiUrl">
<property name="spkcfg_key" stdset="0">
<string>url/api</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblDownloadServers">
<property name="toolTip">
<string>Server addresses are separated with two semicolons (;;).</string>
</property>
<property name="toolTipDuration">
<number>1</number>
</property>
<property name="text">
<string>Download servers</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="edtResourceCachePath">
<property name="spkcfg_key" stdset="0">
<string>dirs/cache</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lblResourceCachePath">
<property name="text">
@ -182,23 +89,10 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblDownloadPath">
<property name="toolTip">
<string/>
</property>
<property name="toolTipDuration">
<number>-1</number>
</property>
<item row="2" column="0">
<widget class="QLabel" name="lblAptRepo">
<property name="text">
<string>Download path</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="lblResourceUrl">
<property name="text">
<string>Store resource URL</string>
<string>APT Repository</string>
</property>
</widget>
</item>
@ -255,6 +149,122 @@
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblLightDarkTheme">
<property name="text">
<string>Light/dark theme</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="edtResourceCachePath">
<property name="spkcfg_key" stdset="0">
<string>dirs/cache</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPlainTextEdit" name="edtDownloadServers">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>80</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>150</height>
</size>
</property>
<property name="baseSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="spkcfg_key" stdset="0">
<string notr="true">download/servers</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cmbLightDarkTheme">
<property name="frame">
<bool>true</bool>
</property>
<property name="spkcfg_key" stdset="0">
<string notr="true">gui/theme</string>
</property>
<item>
<property name="text">
<string>Auto</string>
</property>
</item>
<item>
<property name="text">
<string>Always Light</string>
</property>
</item>
<item>
<property name="text">
<string>Always Dark</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblDownloadPath">
<property name="toolTip">
<string/>
</property>
<property name="toolTipDuration">
<number>-1</number>
</property>
<property name="text">
<string>Download path</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblDownloadServers">
<property name="toolTip">
<string>Server addresses are separated with two semicolons (;;).</string>
</property>
<property name="toolTipDuration">
<number>1</number>
</property>
<property name="text">
<string>Download servers</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="edtApiUrl">
<property name="spkcfg_key" stdset="0">
<string>url/api</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="lblRepoListUrl">
<property name="text">
<string>APT Repository Source</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="edtRepoListUrl"/>
</item>
</layout>
</item>
<item>

@ -22,11 +22,15 @@ namespace SpkUi
virtual void Activated() override;
private slots:
private:
QScrollArea *mMainArea;
QVBoxLayout *mMainLay;
QWidget *mSettingsWidget;
Ui::SpkUiSettings *mSettingsUi;
QString mRepoListUrl;
};
}

@ -2,8 +2,9 @@
#pragma once
#include "spkpkgmgrbase.h"
#include <QProcess>
class SpkPkgMgrApt : public SpkPkgMgrBase
class SpkPkgMgrApt final : public SpkPkgMgrBase
{
Q_OBJECT
@ -21,10 +22,15 @@ class SpkPkgMgrApt : public SpkPkgMgrBase
private:
void CheckInstallerAvailability();
private slots:
void InstallerExited(int, QProcess::ExitStatus);
private:
QAction *mActAptitudeTerm,
*mActAptTerm,
*mActGdebi,
*mActDeepinPkgInst;
QProcess mInstaller;
};

@ -20,8 +20,10 @@ class SpkPkgMgrBase : public QObject
Q_ASSERT(mInstance == nullptr);
mInstance = this;
mActOpen = new QAction(tr("Open package"), this);
mActOpenDir = new QAction(tr("Open containing directory"), this);
mMenu = new QMenu(tr("Package Actions"));
mMenu->addAction(mActOpen);
mMenu->addAction(mActOpenDir);
mMenu->setAttribute(Qt::WA_TranslucentBackground);
mMenu->setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
@ -47,9 +49,12 @@ class SpkPkgMgrBase : public QObject
*/
virtual PkgInstallResult ExecuteInstallation(QString pkgPath, int entryId)
{
Q_UNUSED(entryId);
auto item = mMenu->exec(QCursor::pos());
if(item == mActOpenDir)
QDesktopServices::openUrl(QUrl(SpkUtils::CutPath(pkgPath)));
else if(item == mActOpen)
QDesktopServices::openUrl(QUrl(pkgPath));
return Ignored;
}
@ -60,7 +65,11 @@ class SpkPkgMgrBase : public QObject
*/
virtual PkgInstallResult CliInstall(QString pkgPath)
{
// TODO: print message
qInfo() << tr("Spark Store cannot install your package because no supported "
"packaging system has been found. You shall decide what you "
"want to do with the downloaded package.\n\n"
"File path:")
<< pkgPath;
return Ignored;
}
@ -68,15 +77,15 @@ class SpkPkgMgrBase : public QObject
static SpkPkgMgrBase *Instance() { return mInstance; }
protected:
QAction *mActOpenDir, *mActDesc;
QAction *mActOpenDir, *mActOpen, *mActDesc;
QMenu *mMenu;
int mCurrentItemId; ///< ID of currently installing download item
private:
static SpkPkgMgrBase *mInstance;
signals:
void InstallationEnded(int entryId,
SpkPkgMgrBase::PkgInstallResult success,
QString message);
void ReportInstallResult(int entryId,
SpkPkgMgrBase::PkgInstallResult result,
int exitCode);
};

@ -3,7 +3,7 @@
#include "spkpkgmgrbase.h"
class SpkPkgMgrPacman : public SpkPkgMgrBase
class SpkPkgMgrPacman final : public SpkPkgMgrBase
{
Q_OBJECT

@ -29,5 +29,7 @@ namespace SpkUtils
QString BytesToSize(size_t s, int prec = 2);
bool EnsureDirExists(QString path);
void FillWidget(QWidget* widget, QVariant val);
bool FindViableTerminal();
extern QPair<QString, QString> AvailableTerminal;
}

@ -2,6 +2,7 @@
[url]
api=https://store.deepinos.org/api/
res=http://img.store.deepinos.org.cn/
repo=https://d.store.deepinos.org.cn/store/server.list
[dirs]
cache="*/.cache/spark-store/res/"

@ -13,12 +13,16 @@ SpkPkgMgrApt::SpkPkgMgrApt(QObject *parent) :
mActGdebi = new QAction(tr("GDebi"), this);
mActDeepinPkgInst = new QAction(tr("Deepin Package Installer"), this);
mMenu->addAction(mActAptTerm);
mMenu->addAction(mActAptitudeTerm);
mMenu->addAction(mActGdebi);
mMenu->addAction(mActDeepinPkgInst);
mMenu->insertAction(mActOpen, mActAptTerm);
mMenu->insertAction(mActOpen, mActAptitudeTerm);
mMenu->insertAction(mActOpen, mActGdebi);
mMenu->insertAction(mActOpen, mActDeepinPkgInst);
mMenu->insertSeparator(mActOpen);
mMenu->addSeparator();
mMenu->addAction(mActDesc);
connect(&mInstaller, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &SpkPkgMgrApt::InstallerExited);
}
bool SpkPkgMgrApt::DetectRequirements()
@ -30,8 +34,63 @@ bool SpkPkgMgrApt::DetectRequirements()
SpkPkgMgrBase::PkgInstallResult
SpkPkgMgrApt::ExecuteInstallation(QString pkgPath, int entryId)
{
static auto prompt = tr("\n\n================================\n"
"Press Enter to continue.");
if(mInstaller.state() == QProcess::Running)
{
sNotify(tr("Please wait till the current installation finishes."));
return Ignored;
}
mCurrentItemId = entryId;
CheckInstallerAvailability();
return SpkPkgMgrBase::ExecuteInstallation(pkgPath, entryId);
auto item = mMenu->exec(QCursor::pos());
if(item == mActOpenDir)
{
QDesktopServices::openUrl(QUrl(SpkUtils::CutPath(pkgPath)));
return Ignored;
}
else if(item == mActOpen)
{
QDesktopServices::openUrl(QUrl(pkgPath));
return Ignored;
}
else if(item == mActAptTerm)
{
mInstaller.setProgram(SpkUtils::AvailableTerminal.first);
mInstaller.setArguments({ SpkUtils::AvailableTerminal.second, "pkexec",
"bash", "-c",
QString("apt install '%1'; R=$?; read -p '%2'; exit $R")
.arg(pkgPath, prompt)});
mInstaller.start();
}
else if(item == mActAptitudeTerm)
{
mInstaller.setProgram(SpkUtils::AvailableTerminal.first);
mInstaller.setArguments({ SpkUtils::AvailableTerminal.second, "pkexec",
"bash", "-c",
QString("aptitude install '%1'; R=$?; read -p '%2'; exit $R")
.arg(pkgPath, prompt)});
mInstaller.start();
}
else if(item == mActGdebi)
{
mInstaller.setProgram("pkexec");
mInstaller.setArguments({ "gdebi", "-n", pkgPath });
mInstaller.start();
}
else if(item == mActDeepinPkgInst)
{
mInstaller.setProgram("deepin-deb-installer");
mInstaller.setArguments({ pkgPath });
mInstaller.start();
}
else
return Ignored;
// Startup is very quick and we can risk blocking here a bit
mInstaller.waitForStarted();
return mInstaller.state() == QProcess::Running ? Succeeded : Failed;
}
void SpkPkgMgrApt::CheckInstallerAvailability()
@ -41,4 +100,12 @@ void SpkPkgMgrApt::CheckInstallerAvailability()
mActDeepinPkgInst->setEnabled(QFile::exists("/usr/bin/deepin-deb-installer"));
}
void SpkPkgMgrApt::InstallerExited(int exitCode, QProcess::ExitStatus status)
{
if(status == QProcess::NormalExit)
emit ReportInstallResult(mCurrentItemId, Succeeded, exitCode);
else
emit ReportInstallResult(mCurrentItemId, Failed, exitCode);
}

@ -8,6 +8,7 @@
#include "dtk/spkdtkplugin.h"
#include "gitver.h"
#include "spkmainwindow.h"
#include "spkmsgbox.h"
#include "spkpopup.h"
#include "spkstore.h"
#include "spkutils.h"
@ -75,6 +76,13 @@ SpkStore::SpkStore(bool aCli, QString &aLogPath)
mMainWindow = new SpkMainWindow;
SpkUi::Popup = new SpkUi::SpkPopup(mMainWindow);
if(!SpkUtils::FindViableTerminal())
SpkMsgBox::StaticExec(tr("Cannot find a terminal emulator on the system.\n"
"You will have to specify it in settings later in order\n"
"to use terminal for program output."),
tr("No Terminals Found"),
QMessageBox::Warning);
mMainWindow->show();
}

@ -4,8 +4,11 @@
#include <QJsonDocument>
#include <QDir>
#include <QWidget>
#include <QPair>
#include "spkutils.h"
QPair<QString, QString> SpkUtils::AvailableTerminal = {"", ""};
void SpkUtils::VerifySingleRequest(QPointer<QNetworkReply> aReply)
{
if(aReply.isNull())
@ -112,7 +115,41 @@ bool SpkUtils::EnsureDirExists(QString path)
return true;
}
void SpkUtils::FillWidget(QWidget *widget, QVariant val)
{
// From https://github.com/qt-creator/qt-creator/blob/18f1be58e7937af4f538fc0c47f660cf8c60bda2/src/libs/utils/consoleprocess.cpp
using StrStrPair = QPair<QString, QString>;
Q_GLOBAL_STATIC_WITH_ARGS(QList<StrStrPair>, KnownTerminals,
({
{"x-terminal-emulator", "-e"},
{"xdg-terminal ", ""},
{"xterm", "-e"},
{"aterm", "-e"},
{"Eterm", "-e"},
{"rxvt", "-e"},
{"urxvt", "-e"},
{"xfce4-terminal", "-x"},
{"konsole", "-e "},
{"gnome-terminal", "--"}
}));
bool SpkUtils::FindViableTerminal()
{
auto dirs = qgetenv("PATH").split(':');
QList<QDir> searchDirs;
for(auto &i : dirs)
searchDirs.append(QDir(i));
for(auto &i : *KnownTerminals)
{
for(auto &j : searchDirs)
{
if(j.exists(i.first))
{
AvailableTerminal = i;
return true;
}
}
}
return false;
}