UPD: Изменения, на основе этого патча, заинтегрированы в Qt Creator другим человеком. От меня была только ревью кода.
Во времена, когда проект Qt и все смежные тулы были под управлением VCS Perforce, появился плагин для Qt Creator’а для интеграции работы с этой системой, да вот только в своём развитии он конкретно и застрял в тех стародавних временах. Причина проста: проект переехал на Git, а перфорс нафиг никому не сдался. Как результат: плагин есть, и даже собирается, да вот только считать его хоть малость рабочим… не получается.
Как минимум одна особенность (читать бага), перечёркивает весь (и без того убогий) функционал: он не может определить директорию верхнего уровня для файлов.
При этом, это вроде как работает, когда забиваешь настройки, да вот только они там и поселяются навсегда, прибитые к одному серверу и одному пользователю. А кроме того, за директорию верхнего уровня принимается текущая рабочая директория (читать: та, из которой запущен Qt Creator).
Немного повозившись, родился патч:
From c111318c78acb2b7ddd41533de3577fa7dc64b1d Mon Sep 17 00:00:00 2001
From: Alexander Drozdov <adrozdoff@gmail.com>
Date: Tue, 10 Sep 2013 17:33:55 +1100
Subject: [PATCH] Perforce VCS plugin: fix top-level directory detection
---
src/plugins/perforce/perforcechecker.cpp | 21 ++++++++-
src/plugins/perforce/perforcechecker.h | 5 ++-
src/plugins/perforce/perforceconstants.h | 2 +-
src/plugins/perforce/perforceplugin.cpp | 57 ++++++++++++++++++++-----
src/plugins/perforce/perforceplugin.h | 16 ++++++-
src/plugins/perforce/perforceversioncontrol.cpp | 2 +-
6 files changed, 86 insertions(+), 17 deletions(-)
diff --git a/src/plugins/perforce/perforcechecker.cpp b/src/plugins/perforce/perforcechecker.cpp
index 5971c00..b9b0395 100644
--- a/src/plugins/perforce/perforcechecker.cpp
+++ b/src/plugins/perforce/perforcechecker.cpp
@@ -28,6 +28,7 @@
****************************************************************************/
#include "perforcechecker.h"
+#include "perforceconstants.h"
#include <utils/qtcassert.h>
#include <utils/synchronousprocess.h>
@@ -78,7 +79,8 @@ void PerforceChecker::resetOverrideCursor()
void PerforceChecker::start(const QString &binary,
const QStringList &basicArgs,
- int timeoutMS)
+ int timeoutMS,
+ const QString &workingDirectory)
{
if (isRunning()) {
emitFailed(QLatin1String("Internal error: process still running"));
@@ -91,6 +93,15 @@ void PerforceChecker::start(const QString &binary,
m_binary = binary;
QStringList args = basicArgs;
args << QLatin1String("client") << QLatin1String("-o");
+
+ if (Perforce::Constants::debug)
+ qDebug() << "PerforceChecker::start: [" << workingDirectory << "]" << m_binary << args;
+
+ if (!workingDirectory.isEmpty())
+ {
+ m_process.setWorkingDirectory(workingDirectory);
+ }
+
m_process.start(m_binary, args);
m_process.closeWriteChannel();
// Timeout handling
@@ -105,6 +116,11 @@ void PerforceChecker::start(const QString &binary,
}
}
+bool PerforceChecker::waitForFinished(int msec)
+{
+ return m_process.waitForFinished(msec);
+}
+
void PerforceChecker::slotTimeOut()
{
if (!isRunning())
@@ -169,6 +185,9 @@ static inline QString clientRootFromOutput(const QString &in)
void PerforceChecker::parseOutput(const QString &response)
{
+ if (Perforce::Constants::debug)
+ qDebug() << "PerforceChecker::parseOutput: " << response;
+
if (!response.contains(QLatin1String("View:")) && !response.contains(QLatin1String("//depot/"))) {
emitFailed(tr("The client does not seem to contain any mapped files."));
return;
diff --git a/src/plugins/perforce/perforcechecker.h b/src/plugins/perforce/perforcechecker.h
index e466250..aada848 100644
--- a/src/plugins/perforce/perforcechecker.h
+++ b/src/plugins/perforce/perforcechecker.h
@@ -50,10 +50,13 @@ public:
public slots:
void start(const QString &binary,
const QStringList &basicArgs = QStringList(),
- int timeoutMS = -1);
+ int timeoutMS = -1,
+ const QString &workingDirectory = QString());
bool isRunning() const;
+ bool waitForFinished(int msec = -1);
+
bool useOverideCursor() const;
void setUseOverideCursor(bool v);
diff --git a/src/plugins/perforce/perforceconstants.h b/src/plugins/perforce/perforceconstants.h
index 316fc24..1f8c2a1 100644
--- a/src/plugins/perforce/perforceconstants.h
+++ b/src/plugins/perforce/perforceconstants.h
@@ -55,7 +55,7 @@ const char SUBMIT_CURRENT[] = "Perforce.SubmitCurrentLog";
const char DIFF_SELECTED[] = "Perforce.DiffSelectedFilesInLog";
const char SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.p4.submit";
-enum { debug = 0 };
+enum { debug = 1 };
} // Constants
} // Perforce
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
index 8fd5957..1f9480d 100644
--- a/src/plugins/perforce/perforceplugin.cpp
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -824,7 +824,11 @@ bool PerforcePlugin::managesDirectory(const QString &directory, QString *topLeve
const bool rc = managesDirectoryFstat(directory);
if (topLevel) {
if (rc)
+ {
+ if (Perforce::Constants::debug)
+ qDebug() << "Top Level: " << m_settings.topLevelSymLinkTarget();
*topLevel = m_settings.topLevelSymLinkTarget();
+ }
else
topLevel->clear();
}
@@ -834,28 +838,48 @@ bool PerforcePlugin::managesDirectory(const QString &directory, QString *topLeve
bool PerforcePlugin::managesDirectoryFstat(const QString &directory)
{
if (!m_settings.isValid())
+ {
+ if (Perforce::Constants::debug)
+ qDebug() << "Settings invalid";
return false;
+ }
// Cached?
const ManagedDirectoryCache::const_iterator cit = m_managedDirectoryCache.constFind(directory);
if (cit != m_managedDirectoryCache.constEnd())
- return cit.value();
+ {
+ const DirectoryCacheEntry &entry = cit.value();
+ if (Perforce::Constants::debug)
+ qDebug() << "Directory: " << directory << " is cached and managed: " << entry.isManaged;
+
+ setNewTopLevel(entry.topLevel);
+
+ return entry.isManaged;
+ }
// Determine value and insert into cache
bool managed = false;
do {
// Quick check: Must be at or below top level and not "../../other_path"
const QStringList relativeDirArgs = m_settings.relativeToTopLevelArguments(directory);
if (!relativeDirArgs.empty() && relativeDirArgs.front().startsWith(QLatin1String("..")))
- break;
+ {
+ if (Perforce::Constants::debug)
+ qDebug() << "Directory " << directory << " is a relative path to current top level dir [" << relativeDirArgs << "], try find new top level.";
+ getTopLevel(directory, true);
+ }
// Is it actually managed by perforce?
QStringList args;
args << QLatin1String("fstat") << QLatin1String("-m1") << perforceRelativeFileArguments(relativeDirArgs);
const PerforceResponse result = runP4Cmd(m_settings.topLevel(), args,
RunFullySynchronous);
+
+ if (Perforce::Constants::debug)
+ qDebug() << "Perforce result:\n" << result.stdOut << "\n---\n" << result.stdErr << "\n---\n" << result.message;
+
managed = result.stdOut.contains(QLatin1String("depotFile"))
|| result.stdErr.contains(QLatin1String("... - no such file(s)"));
} while (false);
- m_managedDirectoryCache.insert(directory, managed);
+ m_managedDirectoryCache.insert(directory, DirectoryCacheEntry(managed, m_settings.topLevel()));
return managed;
}
@@ -1489,12 +1513,7 @@ PerforceVersionControl *PerforcePlugin::perforceVersionControl() const
void PerforcePlugin::slotTopLevelFound(const QString &t)
{
- m_settings.setTopLevel(t);
- const QString msg = tr("Perforce repository: %1").
- arg(QDir::toNativeSeparators(t));
- VcsBase::VcsBaseOutputWindow::instance()->appendSilently(msg);
- if (Perforce::Constants::debug)
- qDebug() << "P4: " << t;
+ setNewTopLevel(t);
}
void PerforcePlugin::slotTopLevelFailed(const QString &errorMessage)
@@ -1504,7 +1523,7 @@ void PerforcePlugin::slotTopLevelFailed(const QString &errorMessage)
qDebug() << errorMessage;
}
-void PerforcePlugin::getTopLevel()
+void PerforcePlugin::getTopLevel(const QString &workingDirectory, bool isSync)
{
// Run a new checker
if (m_settings.p4BinaryPath().isEmpty())
@@ -1514,7 +1533,23 @@ void PerforcePlugin::getTopLevel()
connect(checker, SIGNAL(failed(QString)), checker, SLOT(deleteLater()));
connect(checker, SIGNAL(succeeded(QString)), this, SLOT(slotTopLevelFound(QString)));
connect(checker, SIGNAL(succeeded(QString)),checker, SLOT(deleteLater()));
- checker->start(m_settings.p4BinaryPath(), m_settings.commonP4Arguments(QString()), 30000);
+ checker->start(m_settings.p4BinaryPath(), m_settings.commonP4Arguments(QString()), 30000, workingDirectory);
+
+ if (isSync)
+ checker->waitForFinished();
+}
+
+void PerforcePlugin::setNewTopLevel(const QString &newTopLevel)
+{
+ if (m_settings.topLevel() != newTopLevel)
+ {
+ m_settings.setTopLevel(newTopLevel);
+ const QString msg = tr("Perforce repository: %1").
+ arg(QDir::toNativeSeparators(newTopLevel));
+ VcsBase::VcsBaseOutputWindow::instance()->appendSilently(msg);
+ if (Perforce::Constants::debug)
+ qDebug() << "P4: " << newTopLevel;
+ }
}
#ifdef WITH_TESTS
diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h
index 8eeb1e2..8e08500 100644
--- a/src/plugins/perforce/perforceplugin.h
+++ b/src/plugins/perforce/perforceplugin.h
@@ -146,7 +146,18 @@ protected:
private:
- typedef QHash<QString, bool> ManagedDirectoryCache;
+ struct DirectoryCacheEntry
+ {
+ DirectoryCacheEntry(bool isManaged, const QString &topLevel)
+ : isManaged(isManaged),
+ topLevel(topLevel)
+ {}
+
+ bool isManaged;
+ QString topLevel;
+ };
+
+ typedef QHash<QString, DirectoryCacheEntry> ManagedDirectoryCache;
Core::IEditor *showOutputInEditor(const QString& title, const QString output,
int editorType, const QString &source,
@@ -193,7 +204,8 @@ private:
bool isCommitEditorOpen() const;
QSharedPointer<Utils::TempFileSaver> createTemporaryArgumentFile(const QStringList &extraArgs,
QString *errorString) const;
- void getTopLevel();
+ void getTopLevel(const QString &workingDirectory = QString(), bool isSync = false);
+ void setNewTopLevel(const QString &newTopLevel);
QString pendingChangesData();
void updateCheckout(const QString &workingDir = QString(),
diff --git a/src/plugins/perforce/perforceversioncontrol.cpp b/src/plugins/perforce/perforceversioncontrol.cpp
index 19303a6..ad4f35b 100644
--- a/src/plugins/perforce/perforceversioncontrol.cpp
+++ b/src/plugins/perforce/perforceversioncontrol.cpp
@@ -178,7 +178,7 @@ bool PerforceVersionControl::managesDirectory(const QString &directory, QString
QDebug nsp = qDebug().nospace();
nsp << "managesDirectory" << directory << rc;
if (topLevel)
- nsp << topLevel;
+ nsp << *topLevel;
}
return rc;
}
--
1.8.3.msysgit.0