KNewStuff
cache.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (c) 2009 Frederik Gladhorn <gladhorn@kde.org> 00003 Copyright (c) 2010 Matthias Fuchs <mat69@gmx.net> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Lesser General Public 00007 License as published by the Free Software Foundation; either 00008 version 2.1 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public 00016 License along with this library. If not, see <http://www.gnu.org/licenses/>. 00017 */ 00018 00019 #include "cache.h" 00020 00021 #include <QtCore/QFile> 00022 #include <QtCore/QDir> 00023 #include <QtCore/QFileInfo> 00024 #include <QtCore/QXmlStreamReader> 00025 #include <kstandarddirs.h> 00026 #include <kdebug.h> 00027 00028 using namespace KNS3; 00029 00030 typedef QHash<QString, QWeakPointer<Cache> > CacheHash; 00031 K_GLOBAL_STATIC(CacheHash, s_caches) 00032 00033 Cache::Cache(const QString &appName): QObject(0) 00034 { 00035 m_kns2ComponentName = appName; 00036 00037 registryFile = KStandardDirs::locateLocal("data", "knewstuff3/" + appName + ".knsregistry"); 00038 kDebug() << "Using registry file: " << registryFile; 00039 } 00040 00041 QSharedPointer<Cache> Cache::getCache(const QString &appName) 00042 { 00043 CacheHash::const_iterator it = s_caches->find(appName); 00044 if ((it != s_caches->end()) && !(*it).isNull()) { 00045 return QSharedPointer<Cache>(*it); 00046 } 00047 00048 QSharedPointer<Cache> p(new Cache(appName)); 00049 s_caches->insert(appName, QWeakPointer<Cache>(p)); 00050 00051 return p; 00052 } 00053 00054 Cache::~Cache() 00055 { 00056 } 00057 00058 void Cache::readRegistry() 00059 { 00060 // read KNS2 registry first to migrate it 00061 readKns2MetaFiles(); 00062 00063 QFile f(registryFile); 00064 if (!f.open(QIODevice::ReadOnly)) { 00065 kWarning() << "The file " << registryFile << " could not be opened."; 00066 return; 00067 } 00068 00069 QDomDocument doc; 00070 if (!doc.setContent(&f)) { 00071 kWarning() << "The file could not be parsed."; 00072 return; 00073 } 00074 00075 QDomElement root = doc.documentElement(); 00076 if (root.tagName() != "hotnewstuffregistry") { 00077 kWarning() << "The file doesn't seem to be of interest."; 00078 return; 00079 } 00080 00081 QDomElement stuff = root.firstChildElement("stuff"); 00082 while (!stuff.isNull()) { 00083 EntryInternal e; 00084 e.setEntryXML(stuff); 00085 e.setSource(EntryInternal::Cache); 00086 cache.insert(e); 00087 stuff = stuff.nextSiblingElement("stuff"); 00088 } 00089 00090 kDebug() << "Cache read... entries: " << cache.size(); 00091 } 00092 00093 void Cache::readKns2MetaFiles() 00094 { 00095 KStandardDirs d; 00096 kDebug() << "Loading KNS2 registry of files for the component: " << m_kns2ComponentName; 00097 00098 QString realAppName = m_kns2ComponentName.split(':')[0]; 00099 00100 const QStringList dirs = d.findDirs("data", "knewstuff2-entries.registry"); 00101 for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) { 00102 //kDebug() << " + Load from directory '" + (*it) + "'."; 00103 QDir dir((*it)); 00104 const QStringList files = dir.entryList(QDir::Files | QDir::Readable); 00105 for (QStringList::const_iterator fit = files.begin(); fit != files.end(); ++fit) { 00106 QString filepath = (*it) + '/' + (*fit); 00107 00108 kDebug() << " Load from file '" + filepath + "'."; 00109 00110 QFileInfo info(filepath); 00111 QFile f(filepath); 00112 00113 // first see if this file is even for this app 00114 // because the registry contains entries for all apps 00115 // FIXMEE: should be able to do this with a filter on the entryList above probably 00116 QString thisAppName = QString::fromUtf8(QByteArray::fromBase64(info.baseName().toUtf8())); 00117 00118 // NOTE: the ":" needs to always coincide with the separator character used in 00119 // the id(Entry*) method 00120 thisAppName = thisAppName.split(':')[0]; 00121 00122 if (thisAppName != realAppName) { 00123 continue; 00124 } 00125 00126 if (!f.open(QIODevice::ReadOnly)) { 00127 kWarning() << "The file: " << filepath << " could not be opened."; 00128 continue; 00129 } 00130 00131 QDomDocument doc; 00132 if (!doc.setContent(&f)) { 00133 kWarning() << "The file could not be parsed."; 00134 return; 00135 } 00136 kDebug() << "found entry: " << doc.toString(); 00137 00138 QDomElement root = doc.documentElement(); 00139 if (root.tagName() != "ghnsinstall") { 00140 kWarning() << "The file doesn't seem to be of interest."; 00141 return; 00142 } 00143 00144 // The .meta files only contain one entry 00145 QDomElement stuff = root.firstChildElement("stuff"); 00146 EntryInternal e; 00147 e.setEntryXML(stuff); 00148 e.setSource(EntryInternal::Cache); 00149 00150 if (e.payload().startsWith(QLatin1String("http://download.kde.org/khotnewstuff"))) { 00151 // This is 99% sure a opendesktop file, make it a real one. 00152 e.setProviderId(QLatin1String("https://api.opendesktop.org/v1/")); 00153 e.setHomepage(QString(QLatin1String("http://opendesktop.org/content/show.php?content=") + e.uniqueId())); 00154 00155 } else if (e.payload().startsWith(QLatin1String("http://edu.kde.org/contrib/kvtml/"))) { 00156 // kvmtl-1 00157 e.setProviderId("http://edu.kde.org/contrib/kvtml/kvtml.xml"); 00158 } else if (e.payload().startsWith(QLatin1String("http://edu.kde.org/contrib/kvtml2/"))) { 00159 // kvmtl-2 00160 e.setProviderId("http://edu.kde.org/contrib/kvtml2/provider41.xml"); 00161 } else { 00162 // we failed, skip 00163 kWarning() << "Could not load entry: " << filepath; 00164 continue; 00165 } 00166 00167 e.setStatus(Entry::Installed); 00168 00169 cache.insert(e); 00170 QDomDocument tmp("yay"); 00171 tmp.appendChild(e.entryXML()); 00172 kDebug() << "new entry: " << tmp.toString(); 00173 00174 f.close(); 00175 00176 QDir dir; 00177 if (!dir.remove(filepath)) { 00178 kWarning() << "could not delete old kns2 .meta file: " << filepath; 00179 } else { 00180 kDebug() << "Migrated KNS2 entry to KNS3."; 00181 } 00182 00183 } 00184 } 00185 } 00186 00187 EntryInternal::List Cache::registryForProvider(const QString& providerId) 00188 { 00189 EntryInternal::List entries; 00190 foreach (const EntryInternal& e, cache) { 00191 if (e.providerId() == providerId) { 00192 entries.append(e); 00193 } 00194 } 00195 return entries; 00196 } 00197 00198 00199 void Cache::writeRegistry() 00200 { 00201 kDebug() << "Write registry"; 00202 00203 QFile f(registryFile); 00204 if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { 00205 kWarning() << "Cannot write meta information to '" << registryFile << "'." << endl; 00206 return; 00207 } 00208 00209 QDomDocument doc("khotnewstuff3"); 00210 doc.appendChild(doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" )); 00211 QDomElement root = doc.createElement("hotnewstuffregistry"); 00212 doc.appendChild(root); 00213 00214 foreach (const EntryInternal& entry, cache) { 00215 // Write the entry, unless the policy is CacheNever and the entry is not installed. 00216 if (entry.status() == Entry::Installed || entry.status() == Entry::Updateable) { 00217 QDomElement exml = entry.entryXML(); 00218 root.appendChild(exml); 00219 } 00220 } 00221 00222 QTextStream metastream(&f); 00223 metastream << doc.toByteArray(); 00224 00225 f.close(); 00226 } 00227 00228 void Cache::registerChangedEntry(const KNS3::EntryInternal& entry) 00229 { 00230 cache.insert(entry); 00231 } 00232 00233 void Cache::insertRequest(const KNS3::Provider::SearchRequest& request, const KNS3::EntryInternal::List& entries) 00234 { 00235 // append new entries 00236 requestCache[request.hashForRequest()].append(entries); 00237 kDebug() << request.hashForRequest() << " add: " << entries.size() << " keys: " << requestCache.keys(); 00238 } 00239 00240 EntryInternal::List Cache::requestFromCache(const KNS3::Provider::SearchRequest& request) 00241 { 00242 kDebug() << request.hashForRequest(); 00243 return requestCache.value(request.hashForRequest()); 00244 } 00245 00246 #include "cache.moc"
KDE 4.6 API Reference