#include "revisioncontrolplugin.h"
+#include <stdio.h>
+
RevisionControlPlugin::RevisionControlPlugin()
{
}
#include <QTextStream>
SubversionPlugin::SubversionPlugin() :
- m_retrievalDir(),
m_revisionInfoHash(),
m_updateAction(0),
m_showLocalChangesAction(0),
bool SubversionPlugin::beginRetrieval(const QString& directory)
{
Q_ASSERT(directory.endsWith('/'));
- m_retrievalDir = directory;
- const QString path = directory + ".svn/text-base/";
-
- QDir dir(path);
- const QFileInfoList fileInfoList = dir.entryInfoList();
- const int size = fileInfoList.size();
- QString fileName;
- for (int i = 0; i < size; ++i) {
- const QFileInfo fileInfo = fileInfoList.at(i);
- fileName = fileInfo.fileName();
- // Remove the ".svn-base" postfix to be able to compare the filenames
- // in a fast way in SubversionPlugin::revisionState().
- fileName.chop(sizeof(".svn-base") / sizeof(char) - 1);
- if (!fileName.isEmpty()) {
- RevisionInfo info;
- info.size = fileInfo.size();
- info.timeStamp = fileInfo.lastModified();
- m_revisionInfoHash.insert(directory + fileName, info);
+
+ const QString statusCommand = "svn status " + directory;
+ FILE* in = popen(statusCommand.toAscii().data(), "r");
+ if (in == 0) {
+ return false;
+ }
+
+ char buffer[1024];
+ while (fgets(buffer, sizeof(buffer), in) != 0) {
+ RevisionState state = NormalRevision;
+
+ switch (buffer[0]) {
+ case '?': state = UnversionedRevision; break;
+ case 'M': state = LocallyModifiedRevision; break;
+ case 'A': state = AddedRevision; break;
+ case 'D': state = RemovedRevision; break;
+ case 'C': state = ConflictingRevision; break;
+ default: break;
+ }
+
+ QString filePath(buffer);
+ int pos = filePath.indexOf('/');
+ const int length = filePath.length() - pos - 1;
+ filePath = filePath.mid(pos, length);
+ if (!filePath.isEmpty()) {
+ m_revisionInfoHash.insert(filePath, state);
}
}
- return size > 0;
+ m_revisionInfoKeys = m_revisionInfoHash.keys();
+ return true;
}
void SubversionPlugin::endRetrieval()
RevisionControlPlugin::RevisionState SubversionPlugin::revisionState(const KFileItem& item)
{
const QString itemUrl = item.localPath();
- if (item.isDir()) {
- QFile file(itemUrl + "/.svn");
- if (file.open(QIODevice::ReadOnly)) {
- file.close();
- return RevisionControlPlugin::NormalRevision;
- }
- } else if (m_revisionInfoHash.contains(itemUrl)) {
- const RevisionInfo info = m_revisionInfoHash.value(itemUrl);
- const QDateTime localTimeStamp = item.time(KFileItem::ModificationTime).dateTime();
- const QDateTime versionedTimeStamp = info.timeStamp;
-
- if (localTimeStamp > versionedTimeStamp) {
- if ((info.size != item.size()) || !equalRevisionContent(item.name())) {
- return RevisionControlPlugin::LocallyModifiedRevision;
- }
- } else if (localTimeStamp < versionedTimeStamp) {
- if ((info.size != item.size()) || !equalRevisionContent(item.name())) {
- return RevisionControlPlugin::UpdateRequiredRevision;
+ if (m_revisionInfoHash.contains(itemUrl)) {
+ return m_revisionInfoHash.value(itemUrl);
+ }
+
+ if (!item.isDir()) {
+ // files that have not been listed by 'svn status' (= m_revisionInfoHash)
+ // are under revision control per definition
+ return NormalRevision;
+ }
+
+ // The item is a directory. Check whether an item listed by 'svn status' (= m_revisionInfoHash)
+ // is part of this directory. In this case a local modification should be indicated in the
+ // directory already.
+ foreach (const QString& key, m_revisionInfoKeys) {
+ if (key.startsWith(itemUrl)) {
+ const RevisionState state = m_revisionInfoHash.value(key);
+ if (state == LocallyModifiedRevision) {
+ return LocallyModifiedRevision;
}
}
- return RevisionControlPlugin::NormalRevision;
}
- return RevisionControlPlugin::UnversionedRevision;
+ return NormalRevision;
}
QList<QAction*> SubversionPlugin::contextMenuActions(const KFileItemList& items)
}
}
}
-
-bool SubversionPlugin::equalRevisionContent(const QString& name) const
-{
- QFile localFile(m_retrievalDir + '/' + name);
- if (!localFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
- return false;
- }
-
- QFile revisionedFile(m_retrievalDir + "/.svn/text-base/" + name + ".svn-base");
- if (!revisionedFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
- return false;
- }
-
- QTextStream localText(&localFile);
- QTextStream revisionedText(&revisionedFile);
- while (!localText.atEnd() && !revisionedText.atEnd()) {
- if (localText.readLine() != revisionedText.readLine()) {
- return false;
- }
- }
-
- return localText.atEnd() && revisionedText.atEnd();
-}
* has been marked to get added with the next commit.
*/
AddedRevision,
+ /**
+ * The file is under revision control but has been marked
+ * for getting removed with the next commit.
+ */
+ RemovedRevision,
/**
* The file is under revision control and has been locally
* modified. A modification has also been done on the main
*/
void execSvnCommand(const QString& svnCommand);
- /**
- * Returns true, if the content of the local file \p name is equal to the
- * content of the revisioned file.
- */
- bool equalRevisionContent(const QString& name) const;
-
private:
- struct RevisionInfo
- {
- quint64 size;
- QDateTime timeStamp;
- };
-
- QString m_retrievalDir;
- QHash<QString, RevisionInfo> m_revisionInfoHash;
+ QHash<QString, RevisionState> m_revisionInfoHash;
+ QList<QString> m_revisionInfoKeys; // cache for accessing the keys of the hash
QAction* m_updateAction;
QAction* m_showLocalChangesAction;