Commit cd48c5e5 authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Orgad Shaneh
Browse files

IVersionControl: Implement topic cache in the base class



Derivatives need to derive TopicCache, implement its pure virtual
functions and pass it in IVersionControl's constructor.

Change-Id: I3a904c84541fda95eee75296f86441c4bae55d79
Reviewed-by: default avatarTobias Hunger <tobias.hunger@digia.com>
parent c68ebeed
......@@ -28,7 +28,29 @@
****************************************************************************/
#include "iversioncontrol.h"
#include "vcsmanager.h"
#include <utils/qtcassert.h>
#include <QFileInfo>
/*!
* \class Core::IVersionControl::TopicCache
* \brief The TopicCache class stores a {directory -> topic} cache
*
* In order to support topic, an IVersionControl subclass needs to create
* an instance of TopicCache subclass with appropriate overrides for its
* pure virtual functions, and pass this instance to IVersionControl's constructor.
*/
/*!
* \fn Core::IVersionControl::TopicCache::trackFile(const QString &repository)
* Returns path to file that invalidates the cache when modified, for \a repository.
* e.g. for git this file is .git/HEAD
*
* \fn Core::IVersionControl::TopicCache::refreshTopic(const QString &repository)
* Returns current topic for \a repository.
*/
namespace Core {
QString IVersionControl::vcsOpenText() const
......@@ -41,9 +63,14 @@ QString IVersionControl::vcsMakeWritableText() const
return QString();
}
QString IVersionControl::vcsTopic(const QString &)
QString IVersionControl::vcsTopic(const QString &topLevel)
{
return QString();
return m_topicCache ? m_topicCache->topic(topLevel) : QString();
}
IVersionControl::~IVersionControl()
{
delete m_topicCache;
}
IVersionControl::OpenSupportMode IVersionControl::openSupportMode(const QString &fileName) const
......@@ -52,6 +79,30 @@ IVersionControl::OpenSupportMode IVersionControl::openSupportMode(const QString
return NoOpen;
}
IVersionControl::TopicCache::~TopicCache()
{
}
/*!
* Returns topic for repository under \a topLevel.
*
* If the cache for \a topLevel is valid, it will be used. Otherwise it will be refreshed.
*/
QString IVersionControl::TopicCache::topic(const QString &topLevel)
{
QTC_ASSERT(!topLevel.isEmpty(), return QString());
TopicData &data = m_cache[topLevel];
QString file = trackFile(topLevel);
if (file.isEmpty())
return QString();
const QDateTime lastModified = QFileInfo(file).lastModified();
if (lastModified == data.timeStamp)
return data.topic;
data.timeStamp = lastModified;
return data.topic = refreshTopic(topLevel);
}
} // namespace Core
#if defined(WITH_TESTS)
......
......@@ -33,9 +33,10 @@
#include "core_global.h"
#include "id.h"
#include <QDateTime>
#include <QFlags>
#include <QObject>
#include <QString>
#include <QFlags>
namespace Core {
......@@ -64,8 +65,29 @@ public:
OpenMandatory /*!< Files must always be opened by the VCS */
};
IVersionControl() {}
virtual ~IVersionControl() {}
class TopicCache
{
public:
virtual ~TopicCache();
QString topic(const QString &topLevel);
protected:
virtual QString trackFile(const QString &repository) = 0;
virtual QString refreshTopic(const QString &repository) = 0;
private:
struct TopicData
{
QDateTime timeStamp;
QString topic;
};
QHash<QString, TopicData> m_cache;
};
explicit IVersionControl(TopicCache *topicCache = 0) : m_topicCache(topicCache) {}
virtual ~IVersionControl();
virtual QString displayName() const = 0;
virtual Id id() const = 0;
......@@ -158,7 +180,7 @@ public:
/*!
* Topic (e.g. name of the current branch)
*/
virtual QString vcsTopic(const QString &directory);
virtual QString vcsTopic(const QString &topLevel);
/*!
* Display annotation for a file and scroll to line
......@@ -179,6 +201,9 @@ signals:
void repositoryChanged(const QString &repository);
void filesChanged(const QStringList &files);
void configurationChanged();
private:
TopicCache *m_topicCache;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Core::IVersionControl::SettingsFlags)
......
......@@ -2024,28 +2024,13 @@ bool GitClient::synchronousHeadRefs(const QString &workingDirectory, QStringList
return true;
}
struct TopicData
{
QDateTime timeStamp;
QString topic;
};
// Retrieve topic (branch, tag or HEAD hash)
QString GitClient::synchronousTopic(const QString &workingDirectory)
{
static QHash<QString, TopicData> topicCache;
QString gitDir = findGitDirForRepository(workingDirectory);
if (gitDir.isEmpty())
return QString();
TopicData &data = topicCache[gitDir];
QDateTime lastModified = QFileInfo(gitDir + QLatin1String("/HEAD")).lastModified();
if (lastModified == data.timeStamp)
return data.topic;
data.timeStamp = lastModified;
// First try to find branch
QString branch = synchronousCurrentLocalBranch(workingDirectory);
if (!branch.isEmpty())
return data.topic = branch;
return branch;
// Detached HEAD, try a tag or remote branch
QStringList references;
......@@ -2059,10 +2044,8 @@ QString GitClient::synchronousTopic(const QString &workingDirectory)
foreach (const QString &ref, references) {
int derefInd = ref.indexOf(dereference);
if (ref.startsWith(tagStart)) {
return data.topic = ref.mid(tagStart.size(),
(derefInd == -1) ? -1 : derefInd - tagStart.size());
}
if (ref.startsWith(tagStart))
return ref.mid(tagStart.size(), (derefInd == -1) ? -1 : derefInd - tagStart.size());
if (ref.startsWith(remoteStart)) {
remoteBranch = ref.mid(remoteStart.size(),
(derefInd == -1) ? -1 : derefInd - remoteStart.size());
......@@ -2070,7 +2053,7 @@ QString GitClient::synchronousTopic(const QString &workingDirectory)
}
// No tag
return data.topic = remoteBranch.isEmpty() ? tr("Detached HEAD") : remoteBranch;
return remoteBranch.isEmpty() ? tr("Detached HEAD") : remoteBranch;
}
bool GitClient::synchronousRevParseCmd(const QString &workingDirectory, const QString &ref,
......
......@@ -38,7 +38,32 @@
namespace Git {
namespace Internal {
class GitTopicCache : public Core::IVersionControl::TopicCache
{
public:
GitTopicCache(GitClient *client) :
m_client(client)
{
}
protected:
QString trackFile(const QString &repository)
{
const QString gitDir = m_client->findGitDirForRepository(repository);
return gitDir.isEmpty() ? QString() : (gitDir + QLatin1String("/HEAD"));
}
QString refreshTopic(const QString &repository)
{
return m_client->synchronousTopic(repository);
}
private:
GitClient *m_client;
};
GitVersionControl::GitVersionControl(GitClient *client) :
Core::IVersionControl(new GitTopicCache(client)),
m_client(client)
{
}
......@@ -120,7 +145,7 @@ QString GitVersionControl::vcsGetRepositoryURL(const QString &directory)
QString GitVersionControl::vcsTopic(const QString &directory)
{
QString topic = m_client->synchronousTopic(directory);
QString topic = Core::IVersionControl::vcsTopic(directory);
const QString commandInProgress = m_client->commandInProgressDescription(directory);
if (!commandInProgress.isEmpty())
topic += QLatin1String(" (") + commandInProgress + QLatin1Char(')');
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment