void CatalogBuilder::buildCatalog() { progress = CATALOG_PROGRESS_MIN; emit catalogIncrement(progress); catalog->incrementTimestamp(); indexed.clear(); QList<Directory> memDirs = SettingsManager::readCatalogDirectories(); QHash<uint, PluginInfo> pluginsInfo = plugins->getPlugins(); totalItems = memDirs.count() + pluginsInfo.count(); currentItem = 0; while (currentItem < memDirs.count()) { QString cur = platform->expandEnvironmentVars(memDirs[currentItem].name); indexDirectory(cur, memDirs[currentItem].types, memDirs[currentItem].indexDirs, memDirs[currentItem].indexExe, memDirs[currentItem].depth); progressStep(currentItem); } // Don't call the pluginhandler to request catalog because we need to track progress plugins->getCatalogs(catalog, this); catalog->purgeOldItems(); indexed.clear(); progress = CATALOG_PROGRESS_MAX; emit catalogFinished(); }
void FileIndex::indexTree(const std::string& root) { indexDirectory(root); DIR* dp = opendir(root.c_str()); dirent* ep; if ( dp == NULL ) { throw std::runtime_error("Unable to open directory: " + root); } while( (ep = readdir(dp)) ) { std::string filepath = root +"/"+ ep->d_name; bool isDirectory = false; if (ep->d_type != DT_UNKNOWN) { isDirectory = ep->d_type == DT_DIR; } else { struct stat filedata; if (stat(filepath.c_str(), &filedata) == 0) { isDirectory = S_ISDIR(filedata.st_mode); } } if (isDirectory && ep->d_name[0] != '.') { indexTree(filepath); } } closedir(dp); }
bool PackageJobThread::uninstallPackage(const QString &packagePath) { if (!QFile::exists(packagePath)) { d->errorMessage = i18n("%1 does not exist", packagePath); d->errorCode = Package::JobError::PackageFileNotFoundError; return false; } QString pkg; QString root; { // FIXME: remove, pass in packageroot, type and pluginName separately? QStringList ps = packagePath.split('/'); int ix = ps.count() - 1; if (packagePath.endsWith('/')) { ix = ps.count() - 2; } pkg = ps[ix]; ps.pop_back(); root = ps.join('/'); } bool ok = removeFolder(packagePath); if (!ok) { d->errorMessage = i18n("Could not delete package from: %1", packagePath); d->errorCode = Package::JobError::PackageUninstallError; return false; } indexDirectory(root, QStringLiteral("kpluginindex.json")); return true; }
qint32 FileIndexer::updateDatabase() { qint32 count = 0; qDebug() << "Indexing " << _directories.size() << " directories"; foreach (QDir dir, _directories) { count += indexDirectory(dir); }
void CatalogBuilder::indexDirectory(const QString& directory, const QStringList& filters, bool fdirs, bool fbin, int depth) { QString dir = QDir::toNativeSeparators(directory); QDir qd(dir); dir = qd.absolutePath(); QStringList dirs = qd.entryList(QDir::AllDirs); if (depth > 0) { for (int i = 0; i < dirs.count(); ++i) { if (!dirs[i].startsWith(".")) { QString cur = dirs[i]; if (!cur.contains(".lnk")) { #ifdef Q_WS_MAC // Special handling of app directories if (cur.endsWith(".app", Qt::CaseInsensitive)) { CatItem item(dir + "/" + cur); platform->alterItem(&item); catalog->addItem(item); } else #endif // Sleep shoud be here :) CanIHazSleep::msleep(10); indexDirectory(dir + "/" + dirs[i], filters, fdirs, fbin, depth-1); } } } } if (fdirs) { for (int i = 0; i < dirs.count(); ++i) { if (!dirs[i].startsWith(".") && !indexed.contains(dir + "/" + dirs[i])) { bool isShortcut = dirs[i].endsWith(".lnk", Qt::CaseInsensitive); CatItem item(dir + "/" + dirs[i], !isShortcut); catalog->addItem(item); indexed.insert(dir + "/" + dirs[i]); } } } else { // Grab any shortcut directories // This is to work around a QT weirdness that treats shortcuts to directories as actual directories for (int i = 0; i < dirs.count(); ++i) { if (!dirs[i].startsWith(".") && dirs[i].endsWith(".lnk",Qt::CaseInsensitive)) { if (!indexed.contains(dir + "/" + dirs[i])) { CatItem item(dir + "/" + dirs[i], true); catalog->addItem(item); indexed.insert(dir + "/" + dirs[i]); } } } } if (fbin) { QStringList bins = qd.entryList(QDir::Files | QDir::Executable); for (int i = 0; i < bins.count(); ++i) { if (!indexed.contains(dir + "/" + bins[i])) { CatItem item(dir + "/" + bins[i]); catalog->addItem(item); indexed.insert(dir + "/" + bins[i]); } } } // Don't want a null file filter, that matches everything.. if (filters.count() == 0) return; QStringList files = qd.entryList(filters, QDir::Files | QDir::System, QDir::Unsorted ); for (int i = 0; i < files.count(); ++i) { if (!indexed.contains(dir + "/" + files[i])) { CatItem item(dir + "/" + files[i]); platform->alterItem(&item); #ifdef Q_WS_X11 if(item.fullPath.endsWith(".desktop") && item.icon == "") continue; #endif catalog->addItem(item); indexed.insert(dir + "/" + files[i]); } } }
bool PackageJobThread::installPackage(const QString &src, const QString &dest, OperationType operation) { QDir root(dest); if (!root.exists()) { QDir().mkpath(dest); if (!root.exists()) { d->errorMessage = i18n("Could not create package root directory: %1", dest); d->errorCode = Package::JobError::RootCreationError; //qWarning() << "Could not create package root directory: " << dest; return false; } } QFileInfo fileInfo(src); if (!fileInfo.exists()) { d->errorMessage = i18n("No such file: %1", src); d->errorCode = Package::JobError::PackageFileNotFoundError; return false; } QString path; QTemporaryDir tempdir; bool archivedPackage = false; if (fileInfo.isDir()) { // we have a directory, so let's just install what is in there path = src; // make sure we end in a slash! if (!path.endsWith('/')) { path.append('/'); } } else { KArchive *archive = 0; QMimeDatabase db; QMimeType mimetype = db.mimeTypeForFile(src); if (mimetype.inherits(QStringLiteral("application/zip"))) { archive = new KZip(src); } else if (mimetype.inherits(QStringLiteral("application/x-compressed-tar")) || mimetype.inherits(QStringLiteral("application/x-tar")) || mimetype.inherits(QStringLiteral("application/x-bzip-compressed-tar")) || mimetype.inherits(QStringLiteral("application/x-xz")) || mimetype.inherits(QStringLiteral("application/x-lzma"))) { archive = new KTar(src); } else { //qWarning() << "Could not open package file, unsupported archive format:" << src << mimetype.name(); d->errorMessage = i18n("Could not open package file, unsupported archive format: %1 %2", src, mimetype.name()); d->errorCode = Package::JobError::UnsupportedArchiveFormatError; return false; } if (!archive->open(QIODevice::ReadOnly)) { //qWarning() << "Could not open package file:" << src; delete archive; d->errorMessage = i18n("Could not open package file: %1", src); d->errorCode = Package::JobError::PackageOpenError; return false; } archivedPackage = true; path = tempdir.path() + '/'; d->installPath = path; const KArchiveDirectory *source = archive->directory(); source->copyTo(path); QStringList entries = source->entries(); if (entries.count() == 1) { const KArchiveEntry *entry = source->entry(entries[0]); if (entry->isDirectory()) { path.append(entry->name()).append("/"); } } delete archive; } QDir packageDir(path); QFileInfoList entries = packageDir.entryInfoList(*metaDataFiles); KPluginMetaData meta; if (!entries.isEmpty()) { const QString metadataFilePath = entries.first().filePath(); if (metadataFilePath.endsWith(QLatin1String(".desktop"))) meta = KPluginMetaData(metadataFilePath); else { QFile f(metadataFilePath); if(!f.open(QIODevice::ReadOnly)){ qWarning() << "Couldn't open metadata file" << src << path; d->errorMessage = i18n("Could not open metadata file: %1", src); d->errorCode = Package::JobError::MetadataFileMissingError; return false; } QJsonObject metadataObject = QJsonDocument::fromJson(f.readAll()).object(); meta = KPluginMetaData(metadataObject, QString(), metadataFilePath); } } if (!meta.isValid()) { qDebug() << "No metadata file in package" << src << path; d->errorMessage = i18n("No metadata file in package: %1", src); d->errorCode = Package::JobError::MetadataFileMissingError; return false; } QString pluginName = meta.pluginId(); qDebug() << "pluginname: " << meta.pluginId(); if (pluginName.isEmpty()) { //qWarning() << "Package plugin name not specified"; d->errorMessage = i18n("Package plugin name not specified: %1", src); d->errorCode = Package::JobError::PluginNameMissingError; return false; } // Ensure that package names are safe so package uninstall can't inject // bad characters into the paths used for removal. QRegExp validatePluginName("^[\\w-\\.]+$"); // Only allow letters, numbers, underscore and period. if (!validatePluginName.exactMatch(pluginName)) { //qDebug() << "Package plugin name " << pluginName << "contains invalid characters"; d->errorMessage = i18n("Package plugin name %1 contains invalid characters", pluginName); d->errorCode = Package::JobError::PluginNameInvalidError; return false; } QString targetName = dest; if (targetName[targetName.size() - 1] != '/') { targetName.append('/'); } targetName.append(pluginName); if (QFile::exists(targetName)) { if (operation == Update) { KPluginMetaData oldMeta(targetName + QLatin1String("/metadata.desktop")); if (oldMeta.serviceTypes() != meta.serviceTypes()) { d->errorMessage = i18n("The new package has a different type from the old version already installed.", meta.version(), meta.pluginId(), oldMeta.version()); d->errorCode = Package::JobError::UpdatePackageTypeMismatchError; } else if (isVersionNewer(oldMeta.version(), meta.version())) { const bool ok = uninstallPackage(targetName); if (!ok) { d->errorMessage = i18n("Impossible to remove the old installation of %1 located at %2. error: %3", pluginName, targetName, d->errorMessage); d->errorCode = Package::JobError::OldVersionRemovalError; } } else { d->errorMessage = i18n("Not installing version %1 of %2. Version %3 already installed.", meta.version(), meta.pluginId(), oldMeta.version()); d->errorCode = Package::JobError::NewerVersionAlreadyInstalledError; } } else { d->errorMessage = i18n("%1 already exists", targetName); d->errorCode = Package::JobError::PackageAlreadyInstalledError; } if (d->errorCode != KJob::NoError) { d->installPath = targetName; return false; } } //install dependencies const QStringList dependencies = KPluginMetaData::readStringList(meta.rawData(), QStringLiteral("X-KPackage-Dependencies")); for(const QString &dep : dependencies) { QUrl depUrl(dep); if (!installDependency(depUrl)) { d->errorMessage = i18n("Could not install dependency: %1", dep); d->errorCode = Package::JobError::PackageCopyError; return false; } } if (archivedPackage) { // it's in a temp dir, so just move it over. const bool ok = copyFolder(path, targetName); removeFolder(path); if (!ok) { //qWarning() << "Could not move package to destination:" << targetName; d->errorMessage = i18n("Could not move package to destination: %1", targetName); d->errorCode = Package::JobError::PackageMoveError; return false; } } else { // it's a directory containing the stuff, so copy the contents rather // than move them const bool ok = copyFolder(path, targetName); if (!ok) { //qWarning() << "Could not copy package to destination:" << targetName; d->errorMessage = i18n("Could not copy package to destination: %1", targetName); d->errorCode = Package::JobError::PackageCopyError; return false; } } if (archivedPackage) { // no need to remove the temp dir (which has been successfully moved if it's an archive) tempdir.setAutoRemove(false); } indexDirectory(dest, QStringLiteral("kpluginindex.json")); d->installPath = targetName; //qWarning() << "Not updating kbuildsycoca4, since that will go away. Do it yourself for now if needed."; return true; }