mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-03-23 05:49:43 +08:00
适配 APM
This commit is contained in:
BIN
spark-update-tool/spark-update-tool
Executable file
BIN
spark-update-tool/spark-update-tool
Executable file
Binary file not shown.
@@ -8,6 +8,7 @@
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
#include <QFile>
|
||||
#include <QEventLoop>
|
||||
|
||||
AppDelegate::AppDelegate(QObject *parent)
|
||||
: QStyledItemDelegate(parent), m_downloadManager(new DownloadManager(this)), m_installProcess(nullptr) {
|
||||
@@ -21,6 +22,35 @@ AppDelegate::AppDelegate(QObject *parent)
|
||||
qDebug() << (success ? "下载完成:" : "下载失败:") << packageName;
|
||||
if (success) {
|
||||
enqueueInstall(packageName); // 安装完成后再设置 isInstalled
|
||||
} else {
|
||||
// 下载失败,删除已存在的deb包并重新下载
|
||||
QDir tempDir(QDir::tempPath());
|
||||
QStringList debs = tempDir.entryList(QStringList() << QString("%1_*.deb").arg(packageName) << QString("%1*.deb").arg(packageName), QDir::Files);
|
||||
for (const QString &deb : debs) {
|
||||
QString debPath = tempDir.absoluteFilePath(deb);
|
||||
if (QFile::exists(debPath)) {
|
||||
if (QFile::remove(debPath)) {
|
||||
qDebug() << "已删除下载失败的软件包:" << debPath;
|
||||
} else {
|
||||
qWarning() << "删除下载失败的软件包失败:" << debPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 重新开始下载
|
||||
if (m_model) {
|
||||
for (int row = 0; row < m_model->rowCount(); ++row) {
|
||||
QModelIndex index = m_model->index(row, 0);
|
||||
if (index.data(Qt::UserRole + 1).toString() == packageName) {
|
||||
QString downloadUrl = index.data(Qt::UserRole + 7).toString();
|
||||
QString outputPath = QString("%1/%2.metalink").arg(QDir::tempPath(), packageName);
|
||||
m_downloads[packageName] = {0, true};
|
||||
m_downloadManager->startDownload(packageName, downloadUrl, outputPath);
|
||||
emit updateDisplay(packageName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -95,6 +125,7 @@ void AppDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, c
|
||||
QString iconPath = index.data(Qt::UserRole + 4).toString();
|
||||
QString size = index.data(Qt::UserRole + 5).toString();
|
||||
QString description = index.data(Qt::UserRole + 6).toString();
|
||||
QString source = index.data(Qt::UserRole + 9).toString();
|
||||
|
||||
QRect rect = option.rect;
|
||||
int margin = 10, spacing = 6, iconSize = 40;
|
||||
@@ -121,11 +152,51 @@ void AppDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, c
|
||||
int textX = iconRect.right() + margin;
|
||||
int textWidth = rect.width() - textX - 100;
|
||||
|
||||
// 绘制应用名称
|
||||
QRect nameRect(textX, rect.top() + margin, textWidth, 20);
|
||||
painter->setFont(boldFont);
|
||||
QColor nameColor = isIgnored ? QColor("#999999") : QColor("#333333");
|
||||
painter->setPen(nameColor);
|
||||
|
||||
// 计算名称宽度
|
||||
QFontMetrics fontMetrics(boldFont);
|
||||
int nameWidth = fontMetrics.horizontalAdvance(name);
|
||||
|
||||
// 绘制名称
|
||||
painter->drawText(nameRect, Qt::AlignLeft | Qt::AlignVCenter, name);
|
||||
|
||||
// 绘制来源Tag
|
||||
if (!source.isEmpty()) {
|
||||
int tagX = textX + nameWidth + 10;
|
||||
QString tagText;
|
||||
QColor bgColor;
|
||||
QColor textColor;
|
||||
|
||||
if (source == "apm") {
|
||||
tagText = "APM";
|
||||
bgColor = QColor("#3B82F6"); // 蓝色
|
||||
textColor = QColor("#FFFFFF");
|
||||
} else {
|
||||
tagText = "传统deb";
|
||||
bgColor = QColor("#F97316"); // 橙色
|
||||
textColor = QColor("#FFFFFF");
|
||||
}
|
||||
|
||||
int tagWidth = fontMetrics.horizontalAdvance(tagText) + 12;
|
||||
int tagHeight = 18;
|
||||
|
||||
QRect tagRect(tagX, rect.top() + margin + 1, tagWidth, tagHeight);
|
||||
|
||||
// 绘制Tag背景
|
||||
painter->setBrush(bgColor);
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->drawRoundedRect(tagRect, 9, 9);
|
||||
|
||||
// 绘制Tag文本
|
||||
painter->setFont(normalFont);
|
||||
painter->setPen(textColor);
|
||||
painter->drawText(tagRect, Qt::AlignCenter, tagText);
|
||||
}
|
||||
|
||||
QRect versionRect(textX, nameRect.bottom() + spacing, textWidth, 20);
|
||||
painter->setFont(normalFont);
|
||||
@@ -161,15 +232,24 @@ void AppDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, c
|
||||
painter->setPen(QColor("#6B7280"));
|
||||
painter->drawText(unignoreButtonRect, Qt::AlignCenter, "取消忽略");
|
||||
} else if (isDownloading) {
|
||||
// 绘制灰底蓝色进度条
|
||||
QRect progressRect(rect.right() - 270, rect.top() + (rect.height() - 20) / 2, 150, 20);
|
||||
QStyleOptionProgressBar progressBarOption;
|
||||
progressBarOption.rect = progressRect;
|
||||
progressBarOption.minimum = 0;
|
||||
progressBarOption.maximum = 100;
|
||||
progressBarOption.progress = progress;
|
||||
progressBarOption.text = QString("%1%").arg(progress);
|
||||
progressBarOption.textVisible = true;
|
||||
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter);
|
||||
|
||||
// 绘制背景
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(QColor("#E5E7EB"));
|
||||
painter->drawRoundedRect(progressRect, 10, 10);
|
||||
|
||||
// 绘制进度
|
||||
int progressWidth = progressRect.width() * progress / 100;
|
||||
QRect progressFillRect(progressRect.left(), progressRect.top(), progressWidth, progressRect.height());
|
||||
painter->setBrush(QColor("#3B82F6"));
|
||||
painter->drawRoundedRect(progressFillRect, 10, 10);
|
||||
|
||||
// 绘制进度文本
|
||||
painter->setPen(Qt::white);
|
||||
painter->setFont(option.font);
|
||||
painter->drawText(progressRect, Qt::AlignCenter, QString("%1%").arg(progress));
|
||||
|
||||
QRect cancelButtonRect(rect.right() - 80, rect.top() + (rect.height() - 30) / 2, 70, 30);
|
||||
painter->setPen(Qt::NoPen);
|
||||
@@ -266,6 +346,21 @@ bool AppDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||
if (cancelButtonRect.contains(mouseEvent->pos())) {
|
||||
m_downloadManager->cancelDownload(packageName);
|
||||
m_downloads.remove(packageName);
|
||||
|
||||
// 删除未下载完成的软件包
|
||||
QDir tempDir(QDir::tempPath());
|
||||
QStringList debs = tempDir.entryList(QStringList() << QString("%1_*.deb").arg(packageName) << QString("%1*.deb").arg(packageName), QDir::Files);
|
||||
for (const QString &deb : debs) {
|
||||
QString debPath = tempDir.absoluteFilePath(deb);
|
||||
if (QFile::exists(debPath)) {
|
||||
if (QFile::remove(debPath)) {
|
||||
qDebug() << "已删除未下载完成的软件包:" << debPath;
|
||||
} else {
|
||||
qWarning() << "删除未下载完成的软件包失败:" << debPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit updateDisplay(packageName);
|
||||
return true;
|
||||
}
|
||||
@@ -298,19 +393,13 @@ bool AppDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||
}
|
||||
}
|
||||
|
||||
// 如果存在deb包,直接进行安装
|
||||
if (!debPath.isEmpty() && QFile::exists(debPath)) {
|
||||
qDebug() << "发现已存在的deb包,直接进行安装:" << debPath;
|
||||
enqueueInstall(packageName);
|
||||
} else {
|
||||
// 否则触发下载流程
|
||||
QString downloadUrl = index.data(Qt::UserRole + 7).toString();
|
||||
QString outputPath = QString("%1/%2.metalink").arg(QDir::tempPath(), packageName);
|
||||
// 触发下载流程(无论是否存在deb包,都尝试续传)
|
||||
QString downloadUrl = index.data(Qt::UserRole + 7).toString();
|
||||
QString outputPath = QString("%1/%2.metalink").arg(QDir::tempPath(), packageName);
|
||||
|
||||
m_downloads[packageName] = {0, true};
|
||||
m_downloadManager->startDownload(packageName, downloadUrl, outputPath);
|
||||
emit updateDisplay(packageName);
|
||||
}
|
||||
m_downloads[packageName] = {0, true};
|
||||
m_downloadManager->startDownload(packageName, downloadUrl, outputPath);
|
||||
emit updateDisplay(packageName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -384,6 +473,47 @@ void AppDelegate::startNextInstall() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取包的来源信息
|
||||
QString source = "aptss"; // 默认来源
|
||||
if (m_model) {
|
||||
for (int row = 0; row < m_model->rowCount(); ++row) {
|
||||
QModelIndex index = m_model->index(row, 0);
|
||||
if (index.data(Qt::UserRole + 1).toString() == packageName) {
|
||||
source = index.data(Qt::UserRole + 9).toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是APM包,先检查APM中是否存在对应的包,再卸载APTSS版本
|
||||
if (source == "apm") {
|
||||
// 检查APM中是否存在对应的包
|
||||
QProcess checkProcess;
|
||||
QStringList checkArgs;
|
||||
checkArgs << "list" << packageName;
|
||||
checkProcess.start("apm", checkArgs);
|
||||
checkProcess.waitForFinished(30000); // 30秒超时
|
||||
|
||||
QString checkOutput = checkProcess.readAllStandardOutput();
|
||||
if (checkOutput.contains(packageName)) {
|
||||
// APM中存在对应的包,卸载APTSS版本
|
||||
QProcess removeProcess;
|
||||
QStringList removeArgs;
|
||||
removeArgs << "remove" << "--purge" << "-y" << packageName;
|
||||
removeProcess.start("aptss", removeArgs);
|
||||
removeProcess.waitForFinished(30000); // 30秒超时
|
||||
qDebug() << "卸载APTSS版本" << packageName << "退出码:" << removeProcess.exitCode();
|
||||
} else {
|
||||
// APM中不存在对应的包,安装失败
|
||||
qWarning() << "APM中不存在对应的包:" << packageName;
|
||||
m_downloads[packageName].isInstalling = false;
|
||||
emit updateDisplay(packageName);
|
||||
m_installingPackage.clear();
|
||||
startNextInstall();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_installProcess = new QProcess(this);
|
||||
|
||||
QString logPath = QString("/tmp/%1_install.log").arg(packageName);
|
||||
@@ -411,7 +541,7 @@ void AppDelegate::startNextInstall() {
|
||||
qDebug().noquote() << QString::fromLocal8Bit(err);
|
||||
});
|
||||
connect(m_installProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, [this, packageName, logFile, debPath](int exitCode, QProcess::ExitStatus status) {
|
||||
this, [this, packageName, logFile, debPath, source](int exitCode, QProcess::ExitStatus status) {
|
||||
if (logFile) logFile->close();
|
||||
m_downloads[packageName].isInstalling = false;
|
||||
if (exitCode == 0) {
|
||||
@@ -425,6 +555,117 @@ void AppDelegate::startNextInstall() {
|
||||
qWarning() << "删除deb包失败:" << debPath;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 安装失败,尝试从APM安装
|
||||
if (source == "aptss") {
|
||||
qDebug() << "APTSS安装失败,尝试从APM安装:" << packageName;
|
||||
|
||||
// 检查apm命令是否存在
|
||||
QProcess whichProcess;
|
||||
whichProcess.start("which", QStringList() << "apm");
|
||||
whichProcess.waitForFinished(5000);
|
||||
|
||||
if (whichProcess.exitCode() != 0) {
|
||||
// apm命令不存在,先安装apm
|
||||
qDebug() << "apm命令不存在,先安装apm";
|
||||
QProcess installApmProcess;
|
||||
installApmProcess.start("aptss", QStringList() << "install" << "apm" << "-y");
|
||||
installApmProcess.waitForFinished(60000); // 60秒超时
|
||||
|
||||
if (installApmProcess.exitCode() != 0) {
|
||||
qWarning() << "安装apm失败:" << packageName;
|
||||
emit updateDisplay(packageName);
|
||||
m_installProcess->deleteLater();
|
||||
m_installProcess = nullptr;
|
||||
m_installingPackage.clear();
|
||||
startNextInstall();
|
||||
return;
|
||||
}
|
||||
qDebug() << "apm安装成功";
|
||||
}
|
||||
|
||||
// 检查APM中是否存在对应的包
|
||||
QProcess checkProcess;
|
||||
QStringList checkArgs;
|
||||
checkArgs << "list" << packageName;
|
||||
checkProcess.start("apm", checkArgs);
|
||||
checkProcess.waitForFinished(30000); // 30秒超时
|
||||
|
||||
QString checkOutput = checkProcess.readAllStandardOutput();
|
||||
if (checkOutput.contains(packageName)) {
|
||||
// APM中存在对应的包,卸载当前版本
|
||||
QProcess removeProcess;
|
||||
QStringList removeArgs;
|
||||
removeArgs << "remove" << "--purge" << "-y" << packageName;
|
||||
removeProcess.start("aptss", removeArgs);
|
||||
removeProcess.waitForFinished(30000);
|
||||
|
||||
// 从APM获取下载URL,使用与aptssupdater相同的方法
|
||||
QString downloadUrl;
|
||||
QProcess process;
|
||||
QString command = QString("amber-pm-debug /usr/bin/apt -c /opt/durapps/spark-store/bin/apt-fast-conf/aptss-apt.conf download %1 --print-uris").arg(packageName);
|
||||
|
||||
process.start("bash", QStringList() << "-c" << command);
|
||||
if (process.waitForFinished(30000)) { // 30秒超时
|
||||
QString output = process.readAllStandardOutput();
|
||||
// 解析输出格式:'URL' 文件名 大小 SHA512:哈希值
|
||||
QRegularExpression regex(R"('([^']+)'\s+\S+\s+(\d+)\s+SHA512:([^\s]+))");
|
||||
QRegularExpressionMatch match = regex.match(output);
|
||||
|
||||
if (match.hasMatch()) {
|
||||
downloadUrl = match.captured(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!downloadUrl.isEmpty()) {
|
||||
// 使用更新器的下载功能下载APM包
|
||||
QString outputPath = QString("%1/%2.metalink").arg(QDir::tempPath(), packageName);
|
||||
m_downloads[packageName] = {0, true};
|
||||
m_downloadManager->startDownload(packageName, downloadUrl, outputPath);
|
||||
|
||||
// 等待下载完成后再安装
|
||||
QEventLoop loop;
|
||||
connect(m_downloadManager, &DownloadManager::downloadFinished, &loop, [&loop](const QString &, bool) {
|
||||
loop.quit();
|
||||
});
|
||||
loop.exec();
|
||||
|
||||
// 下载完成后,使用APM安装
|
||||
QDir tempDir(QDir::tempPath());
|
||||
QStringList debs = tempDir.entryList(QStringList() << QString("%1_*.deb").arg(packageName) << QString("%1*.deb").arg(packageName), QDir::Files);
|
||||
if (!debs.isEmpty()) {
|
||||
QString apmDebPath = tempDir.absoluteFilePath(debs.first());
|
||||
QProcess apmProcess;
|
||||
QStringList apmArgs;
|
||||
apmArgs << "ssaudit" << apmDebPath;
|
||||
apmProcess.start("apm", apmArgs);
|
||||
apmProcess.waitForFinished(60000); // 60秒超时
|
||||
int apmExitCode = apmProcess.exitCode();
|
||||
qDebug() << "APM安装" << packageName << "退出码:" << apmExitCode;
|
||||
|
||||
// APM安装成功后设置状态
|
||||
if (apmExitCode == 0) {
|
||||
m_downloads[packageName].isInstalling = false;
|
||||
m_downloads[packageName].isInstalled = true;
|
||||
|
||||
// 安装成功后删除deb包
|
||||
if (QFile::exists(apmDebPath)) {
|
||||
if (QFile::remove(apmDebPath)) {
|
||||
qDebug() << "已删除deb包:" << apmDebPath;
|
||||
} else {
|
||||
qWarning() << "删除deb包失败:" << apmDebPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning() << "无法获取APM包的下载URL:" << packageName;
|
||||
}
|
||||
} else {
|
||||
// APM中不存在对应的包,不卸载aptss包
|
||||
qWarning() << "APM中不存在对应的包,安装失败:" << packageName;
|
||||
}
|
||||
}
|
||||
}
|
||||
emit updateDisplay(packageName);
|
||||
m_installProcess->deleteLater();
|
||||
@@ -458,7 +699,7 @@ void AppDelegate::startNextInstall() {
|
||||
qDebug().noquote() << QString::fromLocal8Bit(err);
|
||||
});
|
||||
connect(m_installProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, [this, packageName, debPath](int exitCode, QProcess::ExitStatus /*status*/) {
|
||||
this, [this, packageName, debPath, source](int exitCode, QProcess::ExitStatus /*status*/) {
|
||||
// 如果通过退出码判断安装成功,也删除deb包
|
||||
if (exitCode == 0 && QFile::exists(debPath)) {
|
||||
if (QFile::remove(debPath)) {
|
||||
@@ -466,6 +707,117 @@ void AppDelegate::startNextInstall() {
|
||||
} else {
|
||||
qWarning() << "删除deb包失败:" << debPath;
|
||||
}
|
||||
} else {
|
||||
// 安装失败,尝试从APM安装
|
||||
if (source == "aptss") {
|
||||
qDebug() << "APTSS安装失败,尝试从APM安装:" << packageName;
|
||||
|
||||
// 检查apm命令是否存在
|
||||
QProcess whichProcess;
|
||||
whichProcess.start("which", QStringList() << "apm");
|
||||
whichProcess.waitForFinished(5000);
|
||||
|
||||
if (whichProcess.exitCode() != 0) {
|
||||
// apm命令不存在,先安装apm
|
||||
qDebug() << "apm命令不存在,先安装apm";
|
||||
QProcess installApmProcess;
|
||||
installApmProcess.start("aptss", QStringList() << "install" << "apm" << "-y");
|
||||
installApmProcess.waitForFinished(60000); // 60秒超时
|
||||
|
||||
if (installApmProcess.exitCode() != 0) {
|
||||
qWarning() << "安装apm失败:" << packageName;
|
||||
emit updateDisplay(packageName);
|
||||
m_installProcess->deleteLater();
|
||||
m_installProcess = nullptr;
|
||||
m_installingPackage.clear();
|
||||
startNextInstall();
|
||||
return;
|
||||
}
|
||||
qDebug() << "apm安装成功";
|
||||
}
|
||||
|
||||
// 检查APM中是否存在对应的包
|
||||
QProcess checkProcess;
|
||||
QStringList checkArgs;
|
||||
checkArgs << "list" << packageName;
|
||||
checkProcess.start("apm", checkArgs);
|
||||
checkProcess.waitForFinished(30000); // 30秒超时
|
||||
|
||||
QString checkOutput = checkProcess.readAllStandardOutput();
|
||||
if (checkOutput.contains(packageName)) {
|
||||
// APM中存在对应的包,卸载当前版本
|
||||
QProcess removeProcess;
|
||||
QStringList removeArgs;
|
||||
removeArgs << "remove" << "--purge" << "-y" << packageName;
|
||||
removeProcess.start("aptss", removeArgs);
|
||||
removeProcess.waitForFinished(30000);
|
||||
|
||||
// 从APM获取下载URL,使用与aptssupdater相同的方法
|
||||
QString downloadUrl;
|
||||
QProcess process;
|
||||
QString command = QString("amber-pm-debug /usr/bin/apt -c /opt/durapps/spark-store/bin/apt-fast-conf/aptss-apt.conf download %1 --print-uris").arg(packageName);
|
||||
|
||||
process.start("bash", QStringList() << "-c" << command);
|
||||
if (process.waitForFinished(30000)) { // 30秒超时
|
||||
QString output = process.readAllStandardOutput();
|
||||
// 解析输出格式:'URL' 文件名 大小 SHA512:哈希值
|
||||
QRegularExpression regex(R"('([^']+)'\s+\S+\s+(\d+)\s+SHA512:([^\s]+))");
|
||||
QRegularExpressionMatch match = regex.match(output);
|
||||
|
||||
if (match.hasMatch()) {
|
||||
downloadUrl = match.captured(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!downloadUrl.isEmpty()) {
|
||||
// 使用更新器的下载功能下载APM包
|
||||
QString outputPath = QString("%1/%2.metalink").arg(QDir::tempPath(), packageName);
|
||||
m_downloads[packageName] = {0, true};
|
||||
m_downloadManager->startDownload(packageName, downloadUrl, outputPath);
|
||||
|
||||
// 等待下载完成后再安装
|
||||
QEventLoop loop;
|
||||
connect(m_downloadManager, &DownloadManager::downloadFinished, &loop, [&loop](const QString &, bool) {
|
||||
loop.quit();
|
||||
});
|
||||
loop.exec();
|
||||
|
||||
// 下载完成后,使用APM安装
|
||||
QDir tempDir(QDir::tempPath());
|
||||
QStringList debs = tempDir.entryList(QStringList() << QString("%1_*.deb").arg(packageName) << QString("%1*.deb").arg(packageName), QDir::Files);
|
||||
if (!debs.isEmpty()) {
|
||||
QString apmDebPath = tempDir.absoluteFilePath(debs.first());
|
||||
QProcess apmProcess;
|
||||
QStringList apmArgs;
|
||||
apmArgs << "ssaudit" << apmDebPath;
|
||||
apmProcess.start("apm", apmArgs);
|
||||
apmProcess.waitForFinished(60000); // 60秒超时
|
||||
int apmExitCode = apmProcess.exitCode();
|
||||
qDebug() << "APM安装" << packageName << "退出码:" << apmExitCode;
|
||||
|
||||
// APM安装成功后设置状态
|
||||
if (apmExitCode == 0) {
|
||||
m_downloads[packageName].isInstalling = false;
|
||||
m_downloads[packageName].isInstalled = true;
|
||||
|
||||
// 安装成功后删除deb包
|
||||
if (QFile::exists(apmDebPath)) {
|
||||
if (QFile::remove(apmDebPath)) {
|
||||
qDebug() << "已删除deb包:" << apmDebPath;
|
||||
} else {
|
||||
qWarning() << "删除deb包失败:" << apmDebPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning() << "无法获取APM包的下载URL:" << packageName;
|
||||
}
|
||||
} else {
|
||||
// APM中不存在对应的包,不卸载aptss包
|
||||
qWarning() << "APM中不存在对应的包,安装失败:" << packageName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit updateDisplay(packageName);
|
||||
@@ -477,8 +829,15 @@ void AppDelegate::startNextInstall() {
|
||||
}
|
||||
|
||||
QStringList args;
|
||||
args << debPath << "--no-create-desktop-entry" << "--delete-after-install";
|
||||
m_installProcess->start("ssinstall", args);
|
||||
if (source == "apm") {
|
||||
// APM 包使用 apm ssaudit 安装
|
||||
args << "ssaudit" << debPath;
|
||||
m_installProcess->start("apm", args);
|
||||
} else {
|
||||
// APTSS 包使用 ssinstall 安装
|
||||
args << debPath << "--no-create-desktop-entry" << "--delete-after-install" << "--native";
|
||||
m_installProcess->start("/usr/bin/ssinstall", args);
|
||||
}
|
||||
}
|
||||
|
||||
// 新增槽函数,用于更新旋转角度并触发刷新
|
||||
|
||||
@@ -34,6 +34,8 @@ QVariant AppListModel::data(const QModelIndex &index, int role) const
|
||||
return map.value("download_url"); // 返回下载 URL
|
||||
case Qt::UserRole + 8: // 忽略状态
|
||||
return map.value("ignored");
|
||||
case Qt::UserRole + 9: // 包来源
|
||||
return map.value("source");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
@@ -55,9 +57,10 @@ void AppListModel::setUpdateData(const QJsonArray &updateInfo)
|
||||
map["size"] = obj["size"].toString();
|
||||
map["download_url"] = obj["download_url"].toString(); // 确保设置下载 URL
|
||||
map["ignored"] = obj["ignored"].toBool(); // 设置忽略状态
|
||||
map["source"] = obj["source"].toString(); // 设置包来源
|
||||
m_data.append(map); // 添加到 QList<QVariantMap>
|
||||
|
||||
qDebug() << "设置到模型的包名:" << map["package"].toString() << "忽略状态:" << map["ignored"].toBool();
|
||||
qDebug() << "设置到模型的包名:" << map["package"].toString() << "忽略状态:" << map["ignored"].toBool() << "来源:" << map["source"].toString();
|
||||
qDebug() << "设置到模型的下载 URL:" << map["download_url"].toString(); // 检查设置的数据
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
#include <QTextStream>
|
||||
#include <QRegularExpression>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <qdebug.h>
|
||||
|
||||
aptssUpdater::aptssUpdater(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
packageName = getUpdateablePackages();
|
||||
apmPackageName = getApmUpdateablePackages();
|
||||
}
|
||||
|
||||
QStringList aptssUpdater::getUpdateablePackages()
|
||||
@@ -434,3 +436,219 @@ QJsonArray aptssUpdater::getUpdateInfoAsJson()
|
||||
qDebug()<<jsonArray;
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
QStringList aptssUpdater::getApmUpdateablePackages()
|
||||
{
|
||||
QStringList packageDetails;
|
||||
|
||||
// 检查apm命令是否存在
|
||||
QProcess checkProcess;
|
||||
checkProcess.start("which", QStringList() << "apm");
|
||||
if (!checkProcess.waitForFinished(5000) || checkProcess.exitCode() != 0) {
|
||||
qDebug() << "apm命令不存在,跳过APM更新检查";
|
||||
return packageDetails;
|
||||
}
|
||||
|
||||
QProcess process;
|
||||
QString command = R"(env LANGUAGE=en_US /usr/bin/apm list --upgradable | awk 'NR>1')";
|
||||
|
||||
process.start("bash", QStringList() << "-c" << command);
|
||||
if (!process.waitForFinished(30000)) { // 30秒超时
|
||||
qWarning() << "APM process failed to finish within 30 seconds.";
|
||||
process.kill();
|
||||
return packageDetails;
|
||||
}
|
||||
|
||||
QString output = process.readAllStandardOutput();
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
QStringList lines = output.split('\n', Qt::SkipEmptyParts);
|
||||
#else
|
||||
QStringList lines = output.split('\n', QString::SkipEmptyParts);
|
||||
#endif
|
||||
|
||||
for (const QString &line : lines) {
|
||||
QRegularExpression regex(R"(([\w\-\+\.]+)/\S+\s+([^\s]+)\s+\S+\s+\[upgradable from: ([^\]]+)\])");
|
||||
QRegularExpressionMatch match = regex.match(line);
|
||||
if (match.hasMatch()) {
|
||||
QString name = match.captured(1);
|
||||
QString newVersion = match.captured(2);
|
||||
QString oldVersion = match.captured(3);
|
||||
|
||||
// 检查版本是否相同,相同则跳过
|
||||
if (newVersion == oldVersion) {
|
||||
qDebug() << "跳过版本相同的APM包:" << name << "(" << oldVersion << "→" << newVersion << ")";
|
||||
continue;
|
||||
}
|
||||
|
||||
// 写入内存列表
|
||||
packageDetails << QString("%1: %2 → %3").arg(name, oldVersion, newVersion);
|
||||
}
|
||||
}
|
||||
|
||||
return packageDetails;
|
||||
}
|
||||
|
||||
QJsonArray aptssUpdater::getApmUpdateInfoAsJson()
|
||||
{
|
||||
QJsonArray jsonArray;
|
||||
|
||||
// 解析APM包版本信息
|
||||
QHash<QString, QHash<QString, QString>> packageInfo;
|
||||
for (const QString &pkg : apmPackageName) {
|
||||
QStringList parts = pkg.split(": ");
|
||||
if (parts.size() >= 2) {
|
||||
QString packageName = parts[0];
|
||||
QStringList versions = parts[1].split(" → ");
|
||||
if (versions.size() == 2) {
|
||||
packageInfo[packageName]["current_version"] = versions[0];
|
||||
packageInfo[packageName]["new_version"] = versions[1];
|
||||
packageInfo[packageName]["source"] = "apm";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 构建JSON数组
|
||||
for (const QString &packageName : packageInfo.keys()) {
|
||||
QJsonObject jsonObj;
|
||||
jsonObj["package"] = packageName;
|
||||
|
||||
// 从APM桌面文件中解析应用名称和图标
|
||||
QString displayName = packageName; // 默认使用包名
|
||||
QString iconPath = ":/resources/default_icon.png"; // 默认图标
|
||||
|
||||
// APM应用的desktop文件路径
|
||||
QString apmDesktopPath = QString("/var/lib/apm/apm/files/ace-env/var/lib/apm/%1/entries/applications").arg(packageName);
|
||||
QDir desktopDir(apmDesktopPath);
|
||||
if (desktopDir.exists()) {
|
||||
// 查找desktop文件
|
||||
QStringList desktopFiles = desktopDir.entryList(QStringList() << "*.desktop", QDir::Files);
|
||||
if (!desktopFiles.isEmpty()) {
|
||||
QString desktopFile = desktopDir.absoluteFilePath(desktopFiles.first());
|
||||
QFile file(desktopFile);
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QTextStream in(&file);
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine().trimmed();
|
||||
if (line.startsWith("Name=")) {
|
||||
displayName = line.mid(5).trimmed();
|
||||
} else if (line.startsWith("Icon=")) {
|
||||
QString iconName = line.mid(5).trimmed();
|
||||
// 处理图标路径
|
||||
if (!iconName.contains('/')) {
|
||||
// 查找APM包中的图标
|
||||
QString apmIconPath = QString("/var/lib/apm/apm/files/ace-env/var/lib/apm/%1/entries/icons/hicolor/48x48/apps/%2.png").arg(packageName, iconName);
|
||||
if (QFile::exists(apmIconPath)) {
|
||||
iconPath = apmIconPath;
|
||||
}
|
||||
} else {
|
||||
// 已经是绝对路径
|
||||
if (QFile::exists(iconName)) {
|
||||
iconPath = iconName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取APM包大小和下载信息
|
||||
QString size = "0";
|
||||
QString url = "";
|
||||
QString sha512 = "";
|
||||
|
||||
QProcess process;
|
||||
QString command = QString("amber-pm-debug /usr/bin/apt -c /opt/durapps/spark-store/bin/apt-fast-conf/aptss-apt.conf download %1 --print-uris").arg(packageName);
|
||||
|
||||
process.start("bash", QStringList() << "-c" << command);
|
||||
if (process.waitForFinished(30000)) { // 30秒超时
|
||||
QString output = process.readAllStandardOutput();
|
||||
// 解析输出格式:'URL' 文件名 大小 SHA512:哈希值
|
||||
QRegularExpression regex(R"('([^']+)'\s+\S+\s+(\d+)\s+SHA512:([^\s]+))");
|
||||
QRegularExpressionMatch match = regex.match(output);
|
||||
|
||||
if (match.hasMatch()) {
|
||||
url = match.captured(1);
|
||||
size = match.captured(2);
|
||||
sha512 = match.captured(3);
|
||||
}
|
||||
}
|
||||
|
||||
jsonObj["name"] = displayName;
|
||||
jsonObj["current_version"] = packageInfo[packageName]["current_version"];
|
||||
jsonObj["new_version"] = packageInfo[packageName]["new_version"];
|
||||
jsonObj["icon"] = iconPath;
|
||||
jsonObj["ignored"] = false; // 默认不忽略
|
||||
jsonObj["source"] = "apm";
|
||||
jsonObj["size"] = size;
|
||||
jsonObj["download_url"] = url;
|
||||
jsonObj["sha512"] = sha512;
|
||||
jsonArray.append(jsonObj);
|
||||
}
|
||||
qDebug()<<"APM更新信息:"<<jsonArray;
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
QJsonArray aptssUpdater::mergeUpdateInfo()
|
||||
{
|
||||
QJsonArray aptssInfo = getUpdateInfoAsJson();
|
||||
QJsonArray apmInfo = getApmUpdateInfoAsJson();
|
||||
|
||||
// 创建包名到更新信息的映射
|
||||
QHash<QString, QJsonObject> aptssMap;
|
||||
for (const QJsonValue &value : aptssInfo) {
|
||||
QJsonObject obj = value.toObject();
|
||||
QString packageName = obj["package"].toString();
|
||||
obj["source"] = "aptss";
|
||||
aptssMap[packageName] = obj;
|
||||
}
|
||||
|
||||
QHash<QString, QJsonObject> apmMap;
|
||||
for (const QJsonValue &value : apmInfo) {
|
||||
QJsonObject obj = value.toObject();
|
||||
QString packageName = obj["package"].toString();
|
||||
obj["source"] = "apm";
|
||||
apmMap[packageName] = obj;
|
||||
}
|
||||
|
||||
QJsonArray mergedArray;
|
||||
|
||||
// 处理只在aptss中存在的包
|
||||
for (const QString &packageName : aptssMap.keys()) {
|
||||
if (!apmMap.contains(packageName)) {
|
||||
mergedArray.append(aptssMap[packageName]);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理只在apm中存在的包
|
||||
for (const QString &packageName : apmMap.keys()) {
|
||||
if (!aptssMap.contains(packageName)) {
|
||||
mergedArray.append(apmMap[packageName]);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理在两者中都存在的包
|
||||
for (const QString &packageName : aptssMap.keys()) {
|
||||
if (apmMap.contains(packageName)) {
|
||||
QJsonObject aptssObj = aptssMap[packageName];
|
||||
QJsonObject apmObj = apmMap[packageName];
|
||||
|
||||
// 比较版本
|
||||
QString aptssVersion = aptssObj["new_version"].toString();
|
||||
QString apmVersion = apmObj["new_version"].toString();
|
||||
|
||||
// 这里简化处理,实际应该使用版本比较函数
|
||||
if (apmVersion > aptssVersion) {
|
||||
// APM版本更高,使用APM版本
|
||||
mergedArray.append(apmObj);
|
||||
} else {
|
||||
// APTSS版本更高或相同,不展示该包
|
||||
qDebug() << "APTSS版本更高,不展示APM包:" << packageName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qDebug()<<"合并后的更新信息:"<<mergedArray;
|
||||
return mergedArray;
|
||||
}
|
||||
|
||||
@@ -19,10 +19,17 @@ public:
|
||||
QStringList getPackageIcons(); // 获取包图标列表
|
||||
QJsonArray getUpdateInfoAsJson(); // 获取更新信息的 JSON 格式
|
||||
QString m_tempFilePath;
|
||||
|
||||
// APM 相关方法
|
||||
QStringList getApmUpdateablePackages(); // 查询 APM 可更新包列表及更新内容
|
||||
QJsonArray getApmUpdateInfoAsJson(); // 获取 APM 更新信息的 JSON 格式
|
||||
QJsonArray mergeUpdateInfo(); // 合并 APTSS 和 APM 的更新信息
|
||||
|
||||
signals:
|
||||
private:
|
||||
bool checkDesktopFiles(const QStringList &desktopFiles, QString &appName, const QString &lang, const QString &packageName);
|
||||
QStringList packageName;
|
||||
QStringList apmPackageName; // APM 包列表
|
||||
};
|
||||
|
||||
#endif // APTSSUPDATER_H
|
||||
@@ -39,6 +39,8 @@ void DownloadManager::startDownload(const QString &packageName, const QString &u
|
||||
"--console-log-level=warn",
|
||||
"--summary-interval=1",
|
||||
"--allow-overwrite=true",
|
||||
"--connect-timeout=30",
|
||||
"--max-tries=3",
|
||||
"--dir=" + fileInfo.absolutePath(),
|
||||
"--out=" + fileInfo.fileName(),
|
||||
metalinkUrl
|
||||
|
||||
@@ -229,7 +229,7 @@ void MainWindow::initStyle()
|
||||
void MainWindow::checkUpdates()
|
||||
{
|
||||
aptssUpdater updater;
|
||||
QJsonArray updateInfo = updater.getUpdateInfoAsJson();
|
||||
QJsonArray updateInfo = updater.mergeUpdateInfo();
|
||||
|
||||
// 分离正常应用和忽略应用
|
||||
QJsonArray normalApps;
|
||||
@@ -265,7 +265,7 @@ void MainWindow::checkUpdates()
|
||||
|
||||
for (const auto &item : finalApps) {
|
||||
QJsonObject obj = item.toObject();
|
||||
qDebug() << "模型设置的包名:" << obj["package"].toString() << "忽略状态:" << obj["ignored"].toBool();
|
||||
qDebug() << "模型设置的包名:" << obj["package"].toString() << "忽略状态:" << obj["ignored"].toBool() << "来源:" << obj["source"].toString();
|
||||
qDebug() << "模型设置的下载 URL:" << obj["download_url"].toString(); // 检查模型数据
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user