Solve the problem that the database will delete all info while install desktop files.

This commit is contained in:
JunjieBai 2023-03-15 11:32:42 +08:00 committed by iaom
parent d354773177
commit 4a98056c06
4 changed files with 228 additions and 198 deletions

View File

@ -33,6 +33,9 @@ AppDBManager::AppDBManager(QObject *parent) : QThread(parent), m_database(QSqlDa
{ {
//链接数据库 //链接数据库
if (openDataBase()) { if (openDataBase()) {
//建数据库
buildAppInfoDB();
//监听系统语言变化 //监听系统语言变化
m_lastLocaleNameQsettings = new QSettings(LAST_LOCALE_NAME, QSettings::IniFormat); m_lastLocaleNameQsettings = new QSettings(LAST_LOCALE_NAME, QSettings::IniFormat);
m_localeChanged = false; m_localeChanged = false;
@ -66,7 +69,14 @@ AppDBManager::AppDBManager(QObject *parent) : QThread(parent), m_database(QSqlDa
qDebug() << "app db version need update! old version:" << dbVersion.toDouble() << "new version:" << APP_DATABASE_VERSION.toDouble(); qDebug() << "app db version need update! old version:" << dbVersion.toDouble() << "new version:" << APP_DATABASE_VERSION.toDouble();
} }
//初始化数据库 //版本号改变更新数据库字段
if (m_dbVersionNeedUpdate) {
for (auto iter = m_namesOfAppinfoTable.constBegin(); iter!= m_namesOfAppinfoTable.constEnd(); iter++) {
this->addItem2BackIfNotExist(iter.key(), iter.value());
}
}
//刷新应用数据
QStringList appPaths; QStringList appPaths;
appPaths << GENERAL_APP_DESKTOP_PATH << ANDROID_APP_DESKTOP_PATH appPaths << GENERAL_APP_DESKTOP_PATH << ANDROID_APP_DESKTOP_PATH
<< SNAPD_APP_DESKTOP_PATH << AUTOSTART_APP_DESKTOP_PATH; << SNAPD_APP_DESKTOP_PATH << AUTOSTART_APP_DESKTOP_PATH;
@ -80,107 +90,7 @@ AppDBManager::AppDBManager(QObject *parent) : QThread(parent), m_database(QSqlDa
} }
//初始化FileSystemWatcher //初始化FileSystemWatcher
m_watcher = new FileSystemWatcher; initFileSystemWatcher();
m_watcher->addWatch(GENERAL_APP_DESKTOP_PATH);
QDir androidDir(ANDROID_APP_DESKTOP_PATH);
if(!androidDir.exists()) {
androidDir.mkpath(ANDROID_APP_DESKTOP_PATH);
}
m_watcher->addWatch(ANDROID_APP_DESKTOP_PATH);
m_snapdDir = new QDir(SNAPD_APP_DESKTOP_PATH);
if(!m_snapdDir->exists()) {
m_snapdWatcher = new FileSystemWatcher(false);
QDir dir("/var/lib/snapd");
if (!dir.exists()) {
dir.setPath("/var/lib");
}
m_snapdPath = dir.absolutePath();
m_snapdWatcher->addWatch(m_snapdPath);
} else {
m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH);
}
m_watcher->addWatch(AUTOSTART_APP_DESKTOP_PATH);
connect(m_snapdWatcher, &FileSystemWatcher::created, this, [ = ] (const QString &path, bool isDir) {
if (isDir) {
//监测新增目录为/var/lib/snapd时将其替换为snapdWatcher的watchpath
if (path == "/var/lib/snapd") {
m_snapdWatcher->removeWatch(m_snapdPath);
m_snapdWatcher->addWatch(path);
qDebug() << "~~~~~~~add watch" << path << "~~~~~remove watch" << m_snapdPath;
m_snapdPath = path;
//snapd下的desktop目录可能在还没替换监听目录为/var/lib/snapd时就已经被创建因此需要特别判断
QDir dir("/var/lib/snapd/desktop");
if (dir.exists()) {
if (m_snapdDir->exists()) {
m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH);
m_snapdWatcher->removeWatch(m_snapdPath);
qDebug() << "======add watch" << SNAPD_APP_DESKTOP_PATH << "======remove watch" << m_snapdPath;
}
}
}
//检测到/var/lib/snapd/desktop被创建则将监听目录替换为/var/lib/snapd/desktop/applications
if (path == "/var/lib/snapd/desktop" and m_snapdDir->exists()) {
m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH);
m_snapdWatcher->removeWatch(m_snapdPath);
qDebug() << "======add watch" << SNAPD_APP_DESKTOP_PATH << "======remove watch" << m_snapdPath;
}
}
});
connect(m_watcher, &FileSystemWatcher::created, this, [ = ] (const QString &desktopfp, bool isDir) {
//event is IN_CREATE
if (!isDir and desktopfp.endsWith(".desktop")) {
QStringList appPaths(desktopfp.left(desktopfp.lastIndexOf("/")));
this->refreshAllData2DB(appPaths);
}
});
connect(m_watcher, &FileSystemWatcher::moveTo, this, [ = ] (const QString &desktopfp, bool isDir) {
//event is IN_MOVED_TO
if (!isDir and desktopfp.endsWith(".desktop")) {
this->insertDBItem(desktopfp);
}
});
connect(m_watcher, &FileSystemWatcher::modified, this, [ = ] (const QString &desktopfp) {
//event is IN_MODIFY
if (desktopfp.endsWith(".desktop")) {
this->updateDBItem(desktopfp);
}
});
connect(m_watcher, &FileSystemWatcher::moved, this, [ = ] (const QString &desktopfp, bool isDir) {
//event is IN_MOVED_FROM
if (!isDir) {
if (desktopfp.endsWith(".desktop")) {
this->deleteDBItem(desktopfp);
}
} else {
//event is IN_MOVE_SELF
qWarning() << "Dir:" << desktopfp << "has been moved to other place! Stop the watching of the desktop files in it!";
}
});
connect(m_watcher, &FileSystemWatcher::deleted, this, [ = ] (const QString &desktopfp, bool isDir) {
//event is IN_DELETE
if (!isDir) {
if (desktopfp.endsWith(".desktop")) {
this->deleteDBItem(desktopfp);
}
} else {
//event is IN_DELETE_SELF
qWarning() << "Dir:" << desktopfp << "has been deleted! Stop the watching of the desktop files in it!";
}
});
connect(m_watcher, &FileSystemWatcher::unmounted, this, [ = ] (const QString &desktopfp) {
//event is IN_UNMOUNT
qWarning() << "Dir:" << desktopfp << "has been unmounted! Stop the watching of the desktop files in it!";
});
/* /*
//初始化FileSystemWatcher //初始化FileSystemWatcher
@ -307,6 +217,106 @@ void AppDBManager::buildAppInfoDB()
} }
} }
void AppDBManager::initFileSystemWatcher()
{
m_watcher = new FileSystemWatcher;
m_watcher->addWatch(GENERAL_APP_DESKTOP_PATH);
QDir androidDir(ANDROID_APP_DESKTOP_PATH);
if(!androidDir.exists()) {
androidDir.mkpath(ANDROID_APP_DESKTOP_PATH);
}
m_watcher->addWatch(ANDROID_APP_DESKTOP_PATH);
m_snapdDir = new QDir(SNAPD_APP_DESKTOP_PATH);
if(!m_snapdDir->exists()) {
m_snapdWatcher = new FileSystemWatcher(false);
QDir dir("/var/lib/snapd");
if (!dir.exists()) {
dir.setPath("/var/lib");
}
m_snapdPath = dir.absolutePath();
m_snapdWatcher->addWatch(m_snapdPath);
} else {
m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH);
}
m_watcher->addWatch(AUTOSTART_APP_DESKTOP_PATH);
connect(m_snapdWatcher, &FileSystemWatcher::created, this, [ = ] (const QString &path, bool isDir) {
if (isDir) {
//监测新增目录为/var/lib/snapd时将其替换为snapdWatcher的watchpath
if (path == "/var/lib/snapd") {
m_snapdWatcher->removeWatch(m_snapdPath);
m_snapdWatcher->addWatch(path);
qDebug() << "~~~~~~~add watch" << path << "~~~~~remove watch" << m_snapdPath;
m_snapdPath = path;
//snapd下的desktop目录可能在还没替换监听目录为/var/lib/snapd时就已经被创建因此需要特别判断
QDir dir("/var/lib/snapd/desktop");
if (dir.exists()) {
if (m_snapdDir->exists()) {
m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH);
m_snapdWatcher->removeWatch(m_snapdPath);
qDebug() << "======add watch" << SNAPD_APP_DESKTOP_PATH << "======remove watch" << m_snapdPath;
}
}
}
//检测到/var/lib/snapd/desktop被创建则将监听目录替换为/var/lib/snapd/desktop/applications
if (path == "/var/lib/snapd/desktop" and m_snapdDir->exists()) {
m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH);
m_snapdWatcher->removeWatch(m_snapdPath);
qDebug() << "======add watch" << SNAPD_APP_DESKTOP_PATH << "======remove watch" << m_snapdPath;
}
}
});
connect(m_watcher, &FileSystemWatcher::created, this, [ = ] (const QString &desktopfp, bool isDir) {
//event is IN_CREATE
if (!isDir and desktopfp.endsWith(".desktop")) {
this->insertDBItem(desktopfp);
}
});
connect(m_watcher, &FileSystemWatcher::moveTo, this, [ = ] (const QString &desktopfp, bool isDir) {
//event is IN_MOVED_TO
if (!isDir and desktopfp.endsWith(".desktop")) {
QStringList appPaths(desktopfp.left(desktopfp.lastIndexOf("/")));
this->refreshAllData2DB(appPaths);
}
});
connect(m_watcher, &FileSystemWatcher::modified, this, [ = ] (const QString &desktopfp) {
//event is IN_MODIFY
if (desktopfp.endsWith(".desktop")) {
this->updateDBItem(desktopfp);
}
});
connect(m_watcher, &FileSystemWatcher::moved, this, [ = ] (const QString &desktopfp, bool isDir) {
//event is IN_MOVED_FROM
if (!isDir) {
if (desktopfp.endsWith(".desktop")) {
this->deleteDBItem(desktopfp);
}
} else {
//event is IN_MOVE_SELF
qWarning() << "Dir:" << desktopfp << "has been moved to other place! Stop the watching of the desktop files in it!";
}
});
connect(m_watcher, &FileSystemWatcher::deleted, this, [ = ] (const QString &desktopfp, bool isDir) {
//event is IN_DELETE
if (!isDir) {
if (desktopfp.endsWith(".desktop")) {
this->deleteDBItem(desktopfp);
}
} else {
//event is IN_DELETE_SELF
qWarning() << "Dir:" << desktopfp << "has been deleted! Stop the watching of the desktop files in it!";
}
});
}
void AppDBManager::loadDesktopFilePaths(QString path, QFileInfoList &infolist) void AppDBManager::loadDesktopFilePaths(QString path, QFileInfoList &infolist)
{ {
QDir dir(path); QDir dir(path);
@ -331,8 +341,8 @@ bool AppDBManager::addItem2BackIfNotExist(QString itemName, QString itemDataType
return res; return res;
} }
cmd = QString("ALTER TABLE appInfo ADD '%0' '%1' ").arg(itemName) cmd = QString("ALTER TABLE appInfo ADD '%0' %1 ").arg(itemName)
.arg(itemDataType); .arg(itemDataType);
if (defult != QVariant()) { if (defult != QVariant()) {
//TODO 根据数据类型将初始值转化为对应格式数据 //TODO 根据数据类型将初始值转化为对应格式数据
if (itemDataType == "INT(4)") { if (itemDataType == "INT(4)") {
@ -355,98 +365,10 @@ bool AppDBManager::addItem2BackIfNotExist(QString itemName, QString itemDataType
void AppDBManager::refreshAllData2DB(const QStringList &appPaths) void AppDBManager::refreshAllData2DB(const QStringList &appPaths)
{ {
//版本号改变更新数据库字段 PendingAppInfo items;
if (m_dbVersionNeedUpdate) { items.setHandleType(PendingAppInfo::RefreshDataBase);
for (auto iter = m_namesOfAppinfoTable.constBegin(); iter!= m_namesOfAppinfoTable.constEnd(); iter++) { items.setPathsNeedRefreshData(appPaths);
this->addItem2BackIfNotExist(iter.key(), iter.value()); PendingAppInfoQueue::getAppInfoQueue().enqueue(items);
}
}
bool firstExec = false;
QSqlQuery sql(m_database);
sql.setForwardOnly(true);
QString cmd = "SELECT DESKTOP_FILE_PATH,MD5 FROM APPINFO";
QMap<QString, QString> dataMap;
if (!sql.exec(cmd)) {
qDebug() << "Fail to read database, because: " << m_database.lastError();
this->buildAppInfoDB();
firstExec = true;
} else {
sql.exec(cmd);
while (sql.next()) {
dataMap.insert(sql.value("DESKTOP_FILE_PATH").toString(), sql.value("MD5").toString());
}
}
//遍历desktop文件
QFileInfoList infos;
for (const QString &path : appPaths) {
this->loadDesktopFilePaths(path, infos);
}
if(infos.size() < 1) {
return;
}
XdgDesktopFile desktopfile;
for (int i = 0; i < infos.length(); i++) {
QFileInfo fileInfo = infos.at(i);
QString path = fileInfo.filePath();
//对目录递归
if (fileInfo.isDir()) {
loadDesktopFilePaths(path, infos);
continue;
}
//排除非法路径(黑名单 + 非desktop文件
if (/*m_excludedDesktopfiles.contains(path) or */!path.endsWith(".desktop")) {
continue;
}
desktopfile.load(path);
//排除NoDisplay和NotShowIn字段排除loaclized名字为空
if (/*desktopfile.value("NoDisplay").toString().contains("true") or*/
// desktopfile.value("NotShowIn").toString().contains("UKUI") or
desktopfile.localizedValue("Name").toString().isEmpty()) {
continue;
}
if (!firstExec) {
//数据库有记录
if (dataMap.contains(path)) {
if (!QString::compare(dataMap.value(path), getAppDesktopMd5(path))
and !m_dbVersionNeedUpdate) {
//判断系统语言是否改变
if (m_localeChanged) {
this->updateLocaleData(path);
}
dataMap.remove(path);
continue;
} else {
//数据库有记录但md5值改变或数据库版本需要更新则update
this->updateDBItem(path);
dataMap.remove(path);
continue;
}
} else {
//数据库中没有记录则insert
this->insertDBItem(path);
dataMap.remove(path);
continue;
}
}
//数据库为空则全部insert
this->insertDBItem(path);
dataMap.remove(path);
}
//遍历完成后重置标志位
m_localeChanged = false;
//数据库冗余项直接delete
if (!dataMap.isEmpty()) {
for (auto i = dataMap.constBegin(); i != dataMap.constEnd(); i++) {
this->deleteDBItem(i.key());
}
}
} }
bool AppDBManager::handleLocaleDataUpdate(const QString &desktopFilePath) bool AppDBManager::handleLocaleDataUpdate(const QString &desktopFilePath)
@ -947,6 +869,98 @@ bool AppDBManager::handleLockStateUpdate(const QString &desktopFilePath, int num
return res; return res;
} }
void AppDBManager::handleDataBaseRefresh(const QStringList &appPaths)
{
QMap<QString, QString> dataMap;
QSqlQuery query(m_database);
query.setForwardOnly(true);
QString condition;
for (int i = 0; i < appPaths.size(); i++) {
condition.append("DESKTOP_FILE_PATH LIKE ? OR ");
}
condition = condition.left(condition.lastIndexOf(" OR "));
query.prepare(QString("SELECT DESKTOP_FILE_PATH,MD5 FROM APPINFO WHERE %0").arg(condition));
for (int t = 0; t < appPaths.size(); t++) {
query.bindValue(t, appPaths.at(t) + "/%");
}
if (!query.exec()) {
qWarning() << m_database.lastError() << query.lastError();
} else {
query.exec();
while (query.next()) {
dataMap.insert(query.value("DESKTOP_FILE_PATH").toString(), query.value("MD5").toString());
}
}
//遍历desktop文件
QFileInfoList infos;
for (const QString &path : appPaths) {
this->loadDesktopFilePaths(path, infos);
}
if(infos.size() < 1) {
return;
}
XdgDesktopFile desktopfile;
for (int i = 0; i < infos.length(); i++) {
QFileInfo fileInfo = infos.at(i);
QString path = fileInfo.filePath();
//对目录递归
if (fileInfo.isDir()) {
loadDesktopFilePaths(path, infos);
continue;
}
//排除非法路径非desktop文件
if (!path.endsWith(".desktop")) {
continue;
}
desktopfile.load(path);
//排除loaclized名字为空
if (desktopfile.localizedValue("Name").toString().isEmpty()) {
continue;
}
if (!dataMap.isEmpty()) {
//数据库有记录
if (dataMap.contains(path)) {
if (!QString::compare(dataMap.value(path), getAppDesktopMd5(path)) && !m_dbVersionNeedUpdate) {
//判断系统语言是否改变
if (m_localeChanged) {
this->handleLocaleDataUpdate(path);
}
dataMap.remove(path);
continue;
} else {
//数据库有记录但md5值改变或数据库版本需要更新则update
this->handleDBItemUpdate(path);
dataMap.remove(path);
continue;
}
} else {
//数据库中没有记录则insert
this->handleDBItemInsert(path);
dataMap.remove(path);
continue;
}
}
//数据库为空则全部insert
this->handleDBItemInsert(path);
dataMap.remove(path);
}
//遍历完成后重置标志位
m_localeChanged = false;
//数据库冗余项直接delete
if (!dataMap.isEmpty()) {
for (auto i = dataMap.constBegin(); i != dataMap.constEnd(); i++) {
this->handleDBItemDelete(i.key());
}
}
}
QString AppDBManager::tranPidToDesktopFp(int pid) QString AppDBManager::tranPidToDesktopFp(int pid)
{ {
QString exePath = QFile::symLinkTarget("/proc/" + QString::number(pid) + "/exe"); QString exePath = QFile::symLinkTarget("/proc/" + QString::number(pid) + "/exe");

View File

@ -59,6 +59,7 @@ public:
bool handleFavoritesStateUpdate(const QString &desktopFilePath, int num, bool isOrderChanged = false); bool handleFavoritesStateUpdate(const QString &desktopFilePath, int num, bool isOrderChanged = false);
bool handleTopStateUpdate(const QString &desktopFilePath, int num, bool isOrderChanged = false); bool handleTopStateUpdate(const QString &desktopFilePath, int num, bool isOrderChanged = false);
bool handleLockStateUpdate(const QString &desktopFilePath, int num); bool handleLockStateUpdate(const QString &desktopFilePath, int num);
void handleDataBaseRefresh(const QStringList &appPaths);
public Q_SLOTS: public Q_SLOTS:
//通过pid查找对应的desktop文件 //通过pid查找对应的desktop文件
@ -103,6 +104,9 @@ private:
//创建数据库字段 //创建数据库字段
void buildAppInfoDB(); void buildAppInfoDB();
//初始化fileSystemWatcher
void initFileSystemWatcher();
private: private:
static QMutex s_mutex; static QMutex s_mutex;
bool m_localeChanged; bool m_localeChanged;

View File

@ -19,6 +19,10 @@ void PendingAppInfoQueue::enqueue(const PendingAppInfo &appInfo)
if (index == -1) { if (index == -1) {
m_cache << appInfo; m_cache << appInfo;
} else { } else {
//刷新数据库操作直接插入
if (appInfo.handleType() == PendingAppInfo::RefreshDataBase) {
m_cache << appInfo;
}
//要插入项操作类型为删除,清除之前所有操作,替换为删除 //要插入项操作类型为删除,清除之前所有操作,替换为删除
if (appInfo.handleType() == PendingAppInfo::Delete) { if (appInfo.handleType() == PendingAppInfo::Delete) {
m_cache.removeAll(appInfo); m_cache.removeAll(appInfo);
@ -127,7 +131,7 @@ void PendingAppInfoQueue::processCache()
if (AppDBManager::getInstance()->startTransaction()) { if (AppDBManager::getInstance()->startTransaction()) {
for (const PendingAppInfo &info : m_pendingAppInfos) { for (const PendingAppInfo &info : m_pendingAppInfos) {
PendingAppInfo::HandleTypes handleTypes = info.handleType(); PendingAppInfo::HandleTypes handleTypes = info.handleType();
if (handleTypes <= PendingAppInfo::UpdateLocaleData) { if (handleTypes <= PendingAppInfo::UpdateLocaleData || handleTypes == PendingAppInfo::RefreshDataBase) {
switch (handleTypes) { switch (handleTypes) {
case PendingAppInfo::Delete: case PendingAppInfo::Delete:
AppDBManager::getInstance()->handleDBItemDelete(info.path()); AppDBManager::getInstance()->handleDBItemDelete(info.path());
@ -141,6 +145,9 @@ void PendingAppInfoQueue::processCache()
case PendingAppInfo::UpdateLocaleData: case PendingAppInfo::UpdateLocaleData:
AppDBManager::getInstance()->handleLocaleDataUpdate(info.path()); AppDBManager::getInstance()->handleLocaleDataUpdate(info.path());
break; break;
case PendingAppInfo::RefreshDataBase:
AppDBManager::getInstance()->handleDataBaseRefresh(info.pathsNeedRefreshData());
break;
default: default:
break; break;
} }

View File

@ -2,6 +2,7 @@
#define PENDINGAPPINFO_H #define PENDINGAPPINFO_H
#include <QString> #include <QString>
#include <QStringList>
#include <QFlags> #include <QFlags>
namespace UkuiSearch { namespace UkuiSearch {
@ -17,7 +18,8 @@ public:
UpdateLaunchTimes = 1u << 3, UpdateLaunchTimes = 1u << 3,
UpdateFavorites = 1u << 4, UpdateFavorites = 1u << 4,
UpdateTop = 1u << 5, UpdateTop = 1u << 5,
UpdateLock = 1u << 6 UpdateLock = 1u << 6,
RefreshDataBase = 1u << 7
}; };
Q_DECLARE_FLAGS(HandleTypes, HandleType) Q_DECLARE_FLAGS(HandleTypes, HandleType)
@ -37,6 +39,7 @@ public:
m_isTopPosChanged(isChangeTopPos) {} m_isTopPosChanged(isChangeTopPos) {}
QString path() const {return m_desktopfp;} QString path() const {return m_desktopfp;}
QStringList pathsNeedRefreshData() const {return m_pathsNeedRefreshData;}
HandleTypes handleType() const {return m_handleType;} HandleTypes handleType() const {return m_handleType;}
int favoritesState() const {return m_favoritesState;} int favoritesState() const {return m_favoritesState;}
int topState() const {return m_topState;} int topState() const {return m_topState;}
@ -56,6 +59,7 @@ public:
void setLaunchTimes(int times) {m_launchTimes = times;} void setLaunchTimes(int times) {m_launchTimes = times;}
void setChangeFavoritePos(bool isOrderChanged) {m_isFavoritePosChanged = isOrderChanged;} void setChangeFavoritePos(bool isOrderChanged) {m_isFavoritePosChanged = isOrderChanged;}
void setChangeTopPos(bool isOrderChanged) {m_isTopPosChanged = isOrderChanged;} void setChangeTopPos(bool isOrderChanged) {m_isTopPosChanged = isOrderChanged;}
void setPathsNeedRefreshData (const QStringList& paths) {m_pathsNeedRefreshData = paths;}
void merge(const PendingAppInfo& info) void merge(const PendingAppInfo& info)
{ {
m_handleType |= info.handleType(); m_handleType |= info.handleType();
@ -89,6 +93,7 @@ private:
int m_launchTimes = 0; int m_launchTimes = 0;
bool m_isFavoritePosChanged = false; bool m_isFavoritePosChanged = false;
bool m_isTopPosChanged = false; bool m_isTopPosChanged = false;
QStringList m_pathsNeedRefreshData;
}; };
} }