2 Copyright 2008 David Nolden <david.nolden.kdevelop@art-master.de>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
19 #include "itemrepository.h"
21 #include <QDataStream>
23 #include <kstandarddirs.h>
24 #include <kcomponentdata.h>
25 #include <klockfile.h>
26 #include <kmessagebox.h>
29 #include <interfaces/icore.h>
31 #include "../duchain.h"
36 uint
staticItemRepositoryVersion() {
37 //Increase this to reset incompatible item-repositories
41 AbstractItemRepository::~AbstractItemRepository() {
44 ItemRepositoryRegistry::ItemRepositoryRegistry(QString openPath
, KLockFile::Ptr lock
) : m_mutex(QMutex::Recursive
) {
45 if(!openPath
.isEmpty())
46 open(openPath
, false, lock
);
49 QAtomicInt
& ItemRepositoryRegistry::getCustomCounter(const QString
& identity
, int initialValue
) {
50 if(!m_customCounters
.contains(identity
))
51 m_customCounters
.insert(identity
, new QAtomicInt(initialValue
));
52 return *m_customCounters
[identity
];
55 bool processExists(int pid
) {
56 ///@todo Find a cross-platform way of doing this!
57 QFileInfo
f(QString("/proc/%1").arg(pid
));
61 ///The global item-repository registry that is used by default
62 ItemRepositoryRegistry
& allocateGlobalItemRepositoryRegistry() {
66 KComponentData
component("item repositories temp", QByteArray(), KComponentData::SkipMainComponentRegistration
);
67 // if(ICore::self()) {
68 ///@todo Use the kde directory again, once we know how to get it in this early stage
69 // QString baseDir = KStandardDirs::locateLocal("data", "kdevduchain");
70 QString baseDir
= QDir::homePath() + "/.kdevduchain";
71 KStandardDirs::makeDir(baseDir
);
72 //Since each instance of kdevelop needs an own directory, iterate until we find a not-yet-used one
73 for(int a
= 0; a
< 100; ++a
) {
74 QString specificDir
= baseDir
+ QString("/%1").arg(a
);
75 KStandardDirs::makeDir(specificDir
);
76 kDebug() << "making" << specificDir
;
77 lock
= new KLockFile(specificDir
+ "/lock", component
);
78 KLockFile::LockResult result
= lock
->lock(KLockFile::NoBlockFlag
| KLockFile::ForceFlag
);
82 if(result
!= KLockFile::LockOK
) {
84 QString hostname
, appname
;
85 if(lock
->getLockInfo(pid
, hostname
, appname
)) {
86 if(!processExists(pid
)) {
87 kDebug() << "The process holding" << specificDir
<< "does not exists any more. Re-using the directory.";
88 QFile::remove(specificDir
+ "/lock");
90 if(lock
->lock(KLockFile::NoBlockFlag
| KLockFile::ForceFlag
) != KLockFile::LockOK
) {
91 kWarning() << "Failed to re-establish the lock in" << specificDir
;
100 repoPath
= specificDir
;
101 if(result
== KLockFile::LockStale
)
102 kWarning() << "stale lock detected:" << specificDir
+ "/lock";
107 if(repoPath
.isEmpty()) {
108 kWarning() << "could not create a directory for the duchain data";
110 kDebug() << "picked duchain directory" << repoPath
;
114 static ItemRepositoryRegistry
global(repoPath
, lock
);
118 ///The global item-repository registry that is used by default
119 ItemRepositoryRegistry
& globalItemRepositoryRegistry() {
121 static ItemRepositoryRegistry
& global(allocateGlobalItemRepositoryRegistry());
125 void ItemRepositoryRegistry::registerRepository(AbstractItemRepository
* repository
) {
126 QMutexLocker
lock(&m_mutex
);
127 m_repositories
<< repository
;
128 if(!m_path
.isEmpty()) {
129 if(!repository
->open(m_path
)) {
130 deleteDataDirectory();
131 kError() << "failed to open a repository";
137 QString
ItemRepositoryRegistry::path() const {
138 QMutexLocker
lock(&m_mutex
);
142 void ItemRepositoryRegistry::lockForWriting() {
143 QMutexLocker
lock(&m_mutex
);
145 QFile
f(m_path
+ "/is_writing");
146 f
.open(QIODevice::WriteOnly
);
150 void ItemRepositoryRegistry::unlockForWriting() {
151 QMutexLocker
lock(&m_mutex
);
153 QFile::remove(m_path
+ "/is_writing");
156 void ItemRepositoryRegistry::unRegisterRepository(AbstractItemRepository
* repository
) {
157 QMutexLocker
lock(&m_mutex
);
158 Q_ASSERT(m_repositories
.contains(repository
));
160 m_repositories
.removeAll(repository
);
163 //Recursive delete, copied from a mailing-list
164 //Returns true on success
165 bool removeDirectory(const QDir
&aDir
)
167 bool has_err
= false;
168 if (aDir
.exists())//QDir::NoDotAndDotDot
170 QFileInfoList entries
= aDir
.entryInfoList(QDir::NoDotAndDotDot
|
171 QDir::Dirs
| QDir::Files
);
172 int count
= entries
.size();
173 for (int idx
= 0; ((idx
< count
) && !has_err
); idx
++)
175 QFileInfo entryInfo
= entries
[idx
];
176 QString path
= entryInfo
.absoluteFilePath();
177 if (entryInfo
.isDir())
179 has_err
= !removeDirectory(QDir(path
));
188 if (!aDir
.rmdir(aDir
.absolutePath()))
194 void ItemRepositoryRegistry::deleteDataDirectory() {
195 QMutexLocker
lock(&m_mutex
);
196 QFileInfo
pathInfo(m_path
);
198 Q_ASSERT(removeDirectory(d
));
199 KStandardDirs::makeDir(m_path
);
202 bool ItemRepositoryRegistry::open(const QString
& path
, bool clear
, KLockFile::Ptr lock
) {
203 QMutexLocker
mlock(&m_mutex
);
204 if(m_path
== path
&& !clear
)
207 QFileInfo
wasWriting(path
+ "/is_writing");
208 if(wasWriting
.exists()) {
214 kWarning() << QString("The data-repository at %1 has to be cleared. Either the disk format has changed, or KDevelop crashed while writing the repository").arg(m_path
);
215 // KMessageBox::information( 0, i18n("The data-repository at %1 has to be cleared. Either the disk format has changed, or KDevelop crashed while writing the repository.", m_path ) );
216 deleteDataDirectory();
219 foreach(AbstractItemRepository
* repository
, m_repositories
) {
220 if(!repository
->open(path
)) {
221 deleteDataDirectory();
222 kError() << "failed to open a repository";
227 QFile
f(path
+ "/Counters");
228 if(f
.open(QIODevice::ReadOnly
)) {
229 QDataStream
stream(&f
);
231 while(!stream
.atEnd()) {
232 //Read in all custom counter values
234 stream
>> counterName
;
236 stream
>> counterValue
;
237 if(m_customCounters
.contains(counterName
))
238 *m_customCounters
[counterName
] = counterValue
;
240 getCustomCounter(counterName
, 0) = counterValue
;
243 // kDebug() << "Could not open counter file";
250 void ItemRepositoryRegistry::store() {
251 QMutexLocker
lock(&m_mutex
);
252 foreach(AbstractItemRepository
* repository
, m_repositories
)
255 //Store all custom counter values
256 QFile
f(m_path
+ "/Counters");
257 if(f
.open(QIODevice::WriteOnly
)) {
259 QDataStream
stream(&f
);
260 for(QMap
<QString
, QAtomicInt
*>::const_iterator it
= m_customCounters
.begin(); it
!= m_customCounters
.end(); ++it
) {
262 stream
<< it
.value()->fetchAndAddRelaxed(0);
265 kWarning() << "Could not open counter file for writing";
269 void ItemRepositoryRegistry::close() {
271 QMutexLocker
lock(&m_mutex
);
273 foreach(AbstractItemRepository
* repository
, m_repositories
)
279 ItemRepositoryRegistry::~ItemRepositoryRegistry() {
281 QMutexLocker
lock(&m_mutex
);
282 foreach(QAtomicInt
* counter
, m_customCounters
.values())