Use the output of 'svn status' instead of doing a custom and error-prone .svn-parsing. BTW: this commit is the first done within Dolphin itself :-)

svn path=/trunk/KDE/kdebase/apps/; revision=1003845
This commit is contained in:
Peter Penz 2009-07-28 22:04:00 +00:00
parent 66ad27aba1
commit 47615514f8
2 changed files with 57 additions and 78 deletions

View file

@ -19,6 +19,8 @@
#include "revisioncontrolplugin.h"
#include <stdio.h>
RevisionControlPlugin::RevisionControlPlugin()
{
}
@ -46,7 +48,6 @@ RevisionControlPlugin::~RevisionControlPlugin()
#include <QTextStream>
SubversionPlugin::SubversionPlugin() :
m_retrievalDir(),
m_revisionInfoHash(),
m_updateAction(0),
m_showLocalChangesAction(0),
@ -98,27 +99,36 @@ QString SubversionPlugin::fileName() const
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()
@ -128,30 +138,29 @@ 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;
}
}
return RevisionControlPlugin::NormalRevision;
if (m_revisionInfoHash.contains(itemUrl)) {
return m_revisionInfoHash.value(itemUrl);
}
return RevisionControlPlugin::UnversionedRevision;
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 NormalRevision;
}
QList<QAction*> SubversionPlugin::contextMenuActions(const KFileItemList& items)
@ -268,26 +277,3 @@ void SubversionPlugin::execSvnCommand(const QString& svnCommand)
}
}
}
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();
}

View file

@ -65,6 +65,11 @@ public:
* 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
@ -171,21 +176,9 @@ private:
*/
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;