From 7003b82e2ba68f24c9e5c27107aacd82898ba9cf Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@nokia.com> Date: Thu, 20 May 2010 16:24:39 +0200 Subject: [PATCH] Version control: Improve detection. Merge managesDirectory() and findTopLevelForDirectory() into one giving managesDirectory() an optional topLevel parameter. This removes the need to go up the directory hierarchy twice when checking for Merurial or git and also saves some checks for CVS/Subversion. VCSManager: Check cache in reverse order starting out with the full path first to improve handling of nested repositories. Rubber-stamped-by: con Acked-by: dt --- src/plugins/coreplugin/iversioncontrol.h | 17 ++--- src/plugins/coreplugin/vcsmanager.cpp | 40 +++++++++-- src/plugins/cvs/cvscontrol.cpp | 9 +-- src/plugins/cvs/cvscontrol.h | 3 +- src/plugins/cvs/cvsplugin.cpp | 65 +++++++++--------- src/plugins/cvs/cvsplugin.h | 5 +- src/plugins/git/gitversioncontrol.cpp | 12 ++-- src/plugins/git/gitversioncontrol.h | 3 +- src/plugins/mercurial/mercurialcontrol.cpp | 18 +++-- src/plugins/mercurial/mercurialcontrol.h | 3 +- src/plugins/perforce/perforceplugin.cpp | 22 +++--- src/plugins/perforce/perforceplugin.h | 4 +- .../perforce/perforceversioncontrol.cpp | 22 +++--- src/plugins/perforce/perforceversioncontrol.h | 4 +- src/plugins/subversion/subversioncontrol.cpp | 9 +-- src/plugins/subversion/subversioncontrol.h | 3 +- src/plugins/subversion/subversionplugin.cpp | 67 ++++++++++--------- src/plugins/subversion/subversionplugin.h | 6 +- src/plugins/vcsbase/vcsbaseeditor.cpp | 4 +- 19 files changed, 158 insertions(+), 158 deletions(-) diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h index 8fe0bc038e0..0cd29f94388 100644 --- a/src/plugins/coreplugin/iversioncontrol.h +++ b/src/plugins/coreplugin/iversioncontrol.h @@ -56,21 +56,12 @@ public: /*! * Returns whether files in this directory should be managed with this * version control. + * If \a topLevel is non-null, it should return the topmost directory, + * for which this IVersionControl should be used. The VCSManager assumes + * that all files in the returned directory are managed by the same IVersionControl. */ - virtual bool managesDirectory(const QString &filename) const = 0; - /*! - * This function should return the topmost directory, for which this - * IVersionControl should be used. The VCSManager assumes that all files in - * the returned directory are managed by the same IVersionControl. - * - * Note that this is used as an optimization, so that the VCSManager - * doesn't need to call managesDirectory(..) for each directory. - * - * This function is called after finding out that the directory is managed - * by a specific version control. - */ - virtual QString findTopLevelForDirectory(const QString &directory) const = 0; + virtual bool managesDirectory(const QString &filename, QString *topLevel = 0) const = 0; /*! * Called to query whether a VCS supports the respective operations. diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp index 35d5b2f0644..0221e29c9fa 100644 --- a/src/plugins/coreplugin/vcsmanager.cpp +++ b/src/plugins/coreplugin/vcsmanager.cpp @@ -90,6 +90,18 @@ IVersionControl* VCSManager::findVersionControlForDirectory(const QString &direc QString *topLevelDirectory) { typedef VersionControlCache::const_iterator VersionControlCacheConstIterator; + + if (debug) { + qDebug(">findVersionControlForDirectory %s topLevelPtr %d", + qPrintable(directory), (topLevelDirectory != 0)); + if (debug > 1) { + const VersionControlCacheConstIterator cend = m_d->m_cachedMatches.constEnd(); + for (VersionControlCacheConstIterator it = m_d->m_cachedMatches.constBegin(); it != cend; ++it) + qDebug("Cache %s -> '%s'", qPrintable(it.key()), qPrintable(it.value()->displayName())); + } + } + QTC_ASSERT(!directory.isEmpty(), return 0); + const VersionControlCacheConstIterator cacheEnd = m_d->m_cachedMatches.constEnd(); if (topLevelDirectory) @@ -100,37 +112,51 @@ IVersionControl* VCSManager::findVersionControlForDirectory(const QString &direc if (fullPathIt != cacheEnd) { if (topLevelDirectory) *topLevelDirectory = directory; + if (debug) + qDebug("<findVersionControlForDirectory: full cache match for VCS '%s'", qPrintable(fullPathIt.value()->displayName())); return fullPathIt.value(); } - // Split the path, starting from top, try to find the matching repository - int pos = 0; + // Split the path, trying to find the matching repository. We start from the reverse + // in order to detected nested repositories correctly (say, a git checkout under SVN). + // Note that detection of a nested version control will still fail if the + // above-located version control is detected and entered into the cache first. + // The nested one can then no longer be found due to the splitting of the paths. + int pos = directory.size() - 1; const QChar slash = QLatin1Char('/'); while (true) { - const int index = directory.indexOf(slash, pos); - if (index == -1) + const int index = directory.lastIndexOf(slash, pos); + if (index <= 0) // Stop at '/' or not found break; const QString directoryPart = directory.left(index); const VersionControlCacheConstIterator it = m_d->m_cachedMatches.constFind(directoryPart); if (it != cacheEnd) { if (topLevelDirectory) *topLevelDirectory = it.key(); + if (debug) + qDebug("<findVersionControlForDirectory: cache match for VCS '%s', topLevel: %s", + qPrintable(it.value()->displayName()), qPrintable(it.key())); return it.value(); } - pos = index + 1; + pos = index - 1; } // Nothing: ask the IVersionControls directly, insert the toplevel into the cache. const VersionControlList versionControls = allVersionControls(); foreach (IVersionControl * versionControl, versionControls) { - if (versionControl->managesDirectory(directory)) { - const QString topLevel = versionControl->findTopLevelForDirectory(directory); + QString topLevel; + if (versionControl->managesDirectory(directory, &topLevel)) { m_d->m_cachedMatches.insert(topLevel, versionControl); if (topLevelDirectory) *topLevelDirectory = topLevel; + if (debug) + qDebug("<findVersionControlForDirectory: invocation of '%s' matches: %s", + qPrintable(versionControl->displayName()), qPrintable(topLevel)); return versionControl; } } + if (debug) + qDebug("<findVersionControlForDirectory: No match for %s", qPrintable(directory)); return 0; } diff --git a/src/plugins/cvs/cvscontrol.cpp b/src/plugins/cvs/cvscontrol.cpp index 42462006dfd..dbf8adf4b78 100644 --- a/src/plugins/cvs/cvscontrol.cpp +++ b/src/plugins/cvs/cvscontrol.cpp @@ -120,14 +120,9 @@ bool CVSControl::vcsAnnotate(const QString &file, int line) return true; } -bool CVSControl::managesDirectory(const QString &directory) const +bool CVSControl::managesDirectory(const QString &directory, QString *topLevel) const { - return m_plugin->managesDirectory(directory); -} - -QString CVSControl::findTopLevelForDirectory(const QString &directory) const -{ - return m_plugin->findTopLevelForDirectory(directory); + return m_plugin->managesDirectory(directory, topLevel); } void CVSControl::emitRepositoryChanged(const QString &s) diff --git a/src/plugins/cvs/cvscontrol.h b/src/plugins/cvs/cvscontrol.h index 38a8ccfe8e7..4fd06c2de72 100644 --- a/src/plugins/cvs/cvscontrol.h +++ b/src/plugins/cvs/cvscontrol.h @@ -45,8 +45,7 @@ public: explicit CVSControl(CVSPlugin *plugin); virtual QString displayName() const; - virtual bool managesDirectory(const QString &directory) const; - virtual QString findTopLevelForDirectory(const QString &directory) const; + virtual bool managesDirectory(const QString &directory, QString *topLevel = 0) const; virtual bool supportsOperation(Operation operation) const; virtual bool vcsOpen(const QString &fileName); diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index 1f7e646fe1d..1bdb606be6b 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -827,8 +827,10 @@ void CVSPlugin::slotDescribe(const QString &source, const QString &changeNr) bool CVSPlugin::describe(const QString &file, const QString &changeNr, QString *errorMessage) { - const QString toplevel = findTopLevelForDirectory(QFileInfo(file).absolutePath()); - if (toplevel.isEmpty()) { + + QString toplevel; + const bool manages = managesDirectory(QFileInfo(file).absolutePath(), &toplevel); + if (!manages || toplevel.isEmpty()) { *errorMessage = msgCannotFindTopLevel(file); return false; } @@ -1122,45 +1124,44 @@ bool CVSPlugin::vcsDelete(const QString &workingDir, const QString &rawFileName) /* CVS has a "CVS" directory in each directory it manages. The top level * is the first directory under the directory that does not have it. */ -bool CVSPlugin::managesDirectory(const QString &directory) const +bool CVSPlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */) const { + if (topLevel) + topLevel->clear(); + bool manages = false; const QDir dir(directory); - const bool rc = dir.exists() && managesDirectory(dir); - if (CVS::Constants::debug) - qDebug() << "CVSPlugin::managesDirectory" << directory << rc; - return rc; + do { + if (!dir.exists() || !checkCVSDirectory(dir)) + break; + manages = true; + if (!topLevel) + break; + /* Recursing up, the top level is a child of the first directory that does + * not have a "CVS" directory. The starting directory must be a managed + * one. Go up and try to find the first unmanaged parent dir. */ + QDir lastDirectory = dir; + for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) { + if (!checkCVSDirectory(parentDir)) { + *topLevel = lastDirectory.absolutePath(); + break; + } + } + } while (false); + if (CVS::Constants::debug) { + QDebug nsp = qDebug().nospace(); + nsp << "CVSPlugin::managesDirectory" << directory << manages; + if (topLevel) + nsp << *topLevel; + } + return manages; } -bool CVSPlugin::managesDirectory(const QDir &directory) const +bool CVSPlugin::checkCVSDirectory(const QDir &directory) const { const QString cvsDir = directory.absoluteFilePath(QLatin1String("CVS")); return QFileInfo(cvsDir).isDir(); } -QString CVSPlugin::findTopLevelForDirectory(const QString &directory) const -{ - // Debug wrapper - const QString rc = findTopLevelForDirectoryI(directory); - if (CVS::Constants::debug) - qDebug() << "CVSPlugin::findTopLevelForDirectory" << directory << rc; - return rc; -} - -QString CVSPlugin::findTopLevelForDirectoryI(const QString &directory) const -{ - /* Recursing up, the top level is a child of the first directory that does - * not have a "CVS" directory. The starting directory must be a managed - * one. Go up and try to find the first unmanaged parent dir. */ - QDir lastDirectory = QDir(directory); - if (!lastDirectory.exists() || !managesDirectory(lastDirectory)) - return QString(); - for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) { - if (!managesDirectory(parentDir)) - return lastDirectory.absolutePath(); - } - return QString(); -} - CVSControl *CVSPlugin::cvsVersionControl() const { return static_cast<CVSControl *>(versionControl()); diff --git a/src/plugins/cvs/cvsplugin.h b/src/plugins/cvs/cvsplugin.h index 1548729dff1..c95cb8369f9 100644 --- a/src/plugins/cvs/cvsplugin.h +++ b/src/plugins/cvs/cvsplugin.h @@ -95,8 +95,7 @@ public: // IVersionControl bool vcsAdd(const QString &workingDir, const QString &fileName); bool vcsDelete(const QString &workingDir, const QString &fileName); - bool managesDirectory(const QString &directory) const; - QString findTopLevelForDirectory(const QString &directory) const; + bool managesDirectory(const QString &directory, QString *topLevel = 0) const; static CVSPlugin *cvsPluginInstance(); @@ -145,7 +144,7 @@ private: void filelog(const QString &workingDir, const QStringList &files = QStringList(), bool enableAnnotationContextMenu = false); - bool managesDirectory(const QDir &directory) const; + bool checkCVSDirectory(const QDir &directory) const; QString findTopLevelForDirectoryI(const QString &directory) const; void startCommit(const QString &workingDir, const QStringList &files = QStringList()); bool commit(const QString &messageFile, const QStringList &subVersionFileList); diff --git a/src/plugins/git/gitversioncontrol.cpp b/src/plugins/git/gitversioncontrol.cpp index 65a46e492e1..370e20bb270 100644 --- a/src/plugins/git/gitversioncontrol.cpp +++ b/src/plugins/git/gitversioncontrol.cpp @@ -206,14 +206,12 @@ bool GitVersionControl::vcsRemoveSnapshot(const QString &topLevel, const QString && gitClient()->synchronousStashRemove(topLevel, stashName); } -bool GitVersionControl::managesDirectory(const QString &directory) const +bool GitVersionControl::managesDirectory(const QString &directory, QString *topLevel) const { - return !GitClient::findRepositoryForDirectory(directory).isEmpty(); -} - -QString GitVersionControl::findTopLevelForDirectory(const QString &directory) const -{ - return GitClient::findRepositoryForDirectory(directory); + const QString topLevelFound = GitClient::findRepositoryForDirectory(directory); + if (topLevel) + *topLevel = topLevelFound; + return !topLevelFound.isEmpty(); } bool GitVersionControl::vcsAnnotate(const QString &file, int line) diff --git a/src/plugins/git/gitversioncontrol.h b/src/plugins/git/gitversioncontrol.h index 098d8bef528..35504747a7c 100644 --- a/src/plugins/git/gitversioncontrol.h +++ b/src/plugins/git/gitversioncontrol.h @@ -46,8 +46,7 @@ public: virtual QString displayName() const; - bool managesDirectory(const QString &directory) const; - virtual QString findTopLevelForDirectory(const QString &directory) const; + virtual bool managesDirectory(const QString &directory, QString *topLevel) const; virtual bool supportsOperation(Operation operation) const; virtual bool vcsOpen(const QString &fileName); diff --git a/src/plugins/mercurial/mercurialcontrol.cpp b/src/plugins/mercurial/mercurialcontrol.cpp index e8cf97e1fbd..61342dc3507 100644 --- a/src/plugins/mercurial/mercurialcontrol.cpp +++ b/src/plugins/mercurial/mercurialcontrol.cpp @@ -47,16 +47,13 @@ QString MercurialControl::displayName() const return tr("Mercurial"); } -bool MercurialControl::managesDirectory(const QString &directory) const +bool MercurialControl::managesDirectory(const QString &directory, QString *topLevel) const { QFileInfo dir(directory); - return !mercurialClient->findTopLevelForFile(dir).isEmpty(); -} - -QString MercurialControl::findTopLevelForDirectory(const QString &directory) const -{ - QFileInfo dir(directory); - return mercurialClient->findTopLevelForFile(dir); + const QString topLevelFound = mercurialClient->findTopLevelForFile(dir); + if (topLevel) + *topLevel = topLevelFound; + return !topLevelFound.isEmpty(); } bool MercurialControl::supportsOperation(Operation operation) const @@ -137,8 +134,9 @@ bool MercurialControl::vcsAnnotate(const QString &file, int line) bool MercurialControl::sccManaged(const QString &filename) { const QFileInfo fi(filename); - const QString topLevel = findTopLevelForDirectory(fi.absolutePath()); - if (topLevel.isEmpty()) + QString topLevel; + const bool managed = managesDirectory(fi.absolutePath(), &topLevel); + if (!managed || topLevel.isEmpty()) return false; const QDir topLevelDir(topLevel); return mercurialClient->manifestSync(topLevel, topLevelDir.relativeFilePath(filename)); diff --git a/src/plugins/mercurial/mercurialcontrol.h b/src/plugins/mercurial/mercurialcontrol.h index 02be0951bbc..b74fce99ff8 100644 --- a/src/plugins/mercurial/mercurialcontrol.h +++ b/src/plugins/mercurial/mercurialcontrol.h @@ -50,8 +50,7 @@ public: explicit MercurialControl(MercurialClient *mercurialClient); QString displayName() const; - bool managesDirectory(const QString &filename) const; - QString findTopLevelForDirectory(const QString &directory) const; + bool managesDirectory(const QString &filename, QString *topLevel = 0) const; bool supportsOperation(Operation operation) const; bool vcsOpen(const QString &fileName); bool vcsAdd(const QString &filename); diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index fefa63b6756..4a44dc43a50 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -848,7 +848,20 @@ void PerforcePlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as) m_updateAllAction->setEnabled(true); } -bool PerforcePlugin::managesDirectory(const QString &directory) +bool PerforcePlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */) +{ + const bool rc = managesDirectoryFstat(directory); + if (topLevel) { + if (rc) { + *topLevel = m_settings.topLevelSymLinkTarget(); + } else { + topLevel->clear(); + } + } + return rc; +} + +bool PerforcePlugin::managesDirectoryFstat(const QString &directory) { if (!m_settings.isValid()) return false; @@ -875,13 +888,6 @@ bool PerforcePlugin::managesDirectory(const QString &directory) return managed; } -QString PerforcePlugin::findTopLevelForDirectory(const QString &dir) -{ - if (!m_settings.isValid()) - return QString(); - return managesDirectory(dir) ? m_settings.topLevelSymLinkTarget() : QString(); -} - bool PerforcePlugin::vcsOpen(const QString &workingDir, const QString &fileName) { if (Perforce::Constants::debug) diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h index feddd2bcf6a..1e9cceb3ab5 100644 --- a/src/plugins/perforce/perforceplugin.h +++ b/src/plugins/perforce/perforceplugin.h @@ -84,8 +84,7 @@ public: bool initialize(const QStringList &arguments, QString *error_message); void extensionsInitialized(); - bool managesDirectory(const QString &directory); - QString findTopLevelForDirectory(const QString &directory); + bool managesDirectory(const QString &directory, QString *topLevel = 0); bool vcsOpen(const QString &workingDir, const QString &fileName); bool vcsAdd(const QString &workingDir, const QString &fileName); bool vcsDelete(const QString &workingDir, const QString &filename); @@ -194,6 +193,7 @@ private: void updateCheckout(const QString &workingDir = QString(), const QStringList &dirs = QStringList()); bool revertProject(const QString &workingDir, const QStringList &args, bool unchangedOnly); + bool managesDirectoryFstat(const QString &directory); inline PerforceVersionControl *perforceVersionControl() const; diff --git a/src/plugins/perforce/perforceversioncontrol.cpp b/src/plugins/perforce/perforceversioncontrol.cpp index e715fa7ec8a..2dc414f59cd 100644 --- a/src/plugins/perforce/perforceversioncontrol.cpp +++ b/src/plugins/perforce/perforceversioncontrol.cpp @@ -120,19 +120,15 @@ bool PerforceVersionControl::vcsAnnotate(const QString &file, int line) return true; } -bool PerforceVersionControl::managesDirectory(const QString &directory) const -{ - const bool rc = m_plugin->managesDirectory(directory); - if (Perforce::Constants::debug) - qDebug() << "managesDirectory" << directory << rc; - return rc; -} - -QString PerforceVersionControl::findTopLevelForDirectory(const QString &directory) const -{ - const QString rc = m_plugin->findTopLevelForDirectory(directory); - if (Perforce::Constants::debug) - qDebug() << "findTopLevelForDirectory" << directory << rc; +bool PerforceVersionControl::managesDirectory(const QString &directory, QString *topLevel) const +{ + const bool rc = m_plugin->managesDirectory(directory, topLevel); + if (Perforce::Constants::debug) { + QDebug nsp = qDebug().nospace(); + nsp << "managesDirectory" << directory << rc; + if (topLevel) + nsp << topLevel; + } return rc; } diff --git a/src/plugins/perforce/perforceversioncontrol.h b/src/plugins/perforce/perforceversioncontrol.h index 9fe43af676c..1e14cd2810f 100644 --- a/src/plugins/perforce/perforceversioncontrol.h +++ b/src/plugins/perforce/perforceversioncontrol.h @@ -45,8 +45,8 @@ public: virtual QString displayName() const; - bool managesDirectory(const QString &directory) const; - virtual QString findTopLevelForDirectory(const QString &directory) const; + virtual bool managesDirectory(const QString &directory, QString *topLevel = 0) const; + virtual bool supportsOperation(Operation operation) const; virtual bool vcsOpen(const QString &fileName); diff --git a/src/plugins/subversion/subversioncontrol.cpp b/src/plugins/subversion/subversioncontrol.cpp index f7b4648dcb8..f25fc3ab6a2 100644 --- a/src/plugins/subversion/subversioncontrol.cpp +++ b/src/plugins/subversion/subversioncontrol.cpp @@ -114,14 +114,9 @@ bool SubversionControl::vcsRemoveSnapshot(const QString &, const QString &) return false; } -bool SubversionControl::managesDirectory(const QString &directory) const +bool SubversionControl::managesDirectory(const QString &directory, QString *topLevel) const { - return m_plugin->managesDirectory(directory); -} - -QString SubversionControl::findTopLevelForDirectory(const QString &directory) const -{ - return m_plugin->findTopLevelForDirectory(directory); + return m_plugin->managesDirectory(directory, topLevel); } bool SubversionControl::vcsAnnotate(const QString &file, int line) diff --git a/src/plugins/subversion/subversioncontrol.h b/src/plugins/subversion/subversioncontrol.h index 8389f822495..5610059d661 100644 --- a/src/plugins/subversion/subversioncontrol.h +++ b/src/plugins/subversion/subversioncontrol.h @@ -45,8 +45,7 @@ public: explicit SubversionControl(SubversionPlugin *plugin); virtual QString displayName() const; - virtual bool managesDirectory(const QString &directory) const; - virtual QString findTopLevelForDirectory(const QString &directory) const; + virtual bool managesDirectory(const QString &directory, QString *topLevel = 0) const; virtual bool supportsOperation(Operation operation) const; virtual bool vcsOpen(const QString &fileName); diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 857bad47313..ff299b19129 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -940,8 +940,9 @@ void SubversionPlugin::describe(const QString &source, const QString &changeNr) // To describe a complete change, find the top level and then do //svn diff -r 472958:472959 <top level> const QFileInfo fi(source); - const QString topLevel = findTopLevelForDirectory(fi.isDir() ? source : fi.absolutePath()); - if (topLevel.isEmpty()) + QString topLevel; + const bool manages = managesDirectory(fi.isDir() ? source : fi.absolutePath(), &topLevel); + if (!manages || topLevel.isEmpty()) return; if (Subversion::Constants::debug) qDebug() << Q_FUNC_INFO << source << topLevel << changeNr; @@ -1184,7 +1185,7 @@ bool SubversionPlugin::vcsAdd14(const QString &workingDir, const QString &rawFil if (!path.isEmpty()) path += slash; path += relativePath.at(p); - if (!managesDirectory(QDir(path))) { + if (!checkSVNSubDir(QDir(path))) { QStringList addDirArgs; addDirArgs << QLatin1String("add") << QLatin1String("--non-recursive") << QDir::toNativeSeparators(path); const SubversionResponse addDirResponse = runSvn(workingDir, addDirArgs, m_settings.timeOutMS(), true); @@ -1224,16 +1225,40 @@ bool SubversionPlugin::vcsMove(const QString &workingDir, const QString &from, c /* Subversion has ".svn" directory in each directory * it manages. The top level is the first directory * under the directory that does not have a ".svn". */ -bool SubversionPlugin::managesDirectory(const QString &directory) const +bool SubversionPlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */) const { const QDir dir(directory); - const bool rc = dir.exists() && managesDirectory(dir); - if (Subversion::Constants::debug) - qDebug() << "SubversionPlugin::managesDirectory" << directory << rc; - return rc; + if (topLevel) + topLevel->clear(); + bool manages = false; + do { + if (!dir.exists() || !checkSVNSubDir(dir)) + break; + manages = true; + if (!topLevel) + break; + /* Recursing up, the top level is a child of the first directory that does + * not have a ".svn" directory. The starting directory must be a managed + * one. Go up and try to find the first unmanaged parent dir. */ + QDir lastDirectory = dir; + for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) { + if (!checkSVNSubDir(parentDir)) { + *topLevel = lastDirectory.absolutePath(); + break; + } + } + } while (false); + if (Subversion::Constants::debug) { + QDebug nsp = qDebug().nospace(); + nsp << "SubversionPlugin::managesDirectory" << directory << manages; + if (topLevel) + nsp << *topLevel; + } + return manages; } -bool SubversionPlugin::managesDirectory(const QDir &directory) const +// Check whether SVN management subdirs exist. +bool SubversionPlugin::checkSVNSubDir(const QDir &directory) const { const int dirCount = m_svnDirectories.size(); for (int i = 0; i < dirCount; i++) { @@ -1244,30 +1269,6 @@ bool SubversionPlugin::managesDirectory(const QDir &directory) const return false; } -QString SubversionPlugin::findTopLevelForDirectory(const QString &directory) const -{ - // Debug wrapper - const QString rc = findTopLevelForDirectoryI(directory); - if (Subversion::Constants::debug) - qDebug() << "SubversionPlugin::findTopLevelForDirectory" << directory << rc; - return rc; -} - -QString SubversionPlugin::findTopLevelForDirectoryI(const QString &directory) const -{ - /* Recursing up, the top level is a child of the first directory that does - * not have a ".svn" directory. The starting directory must be a managed - * one. Go up and try to find the first unmanaged parent dir. */ - QDir lastDirectory = QDir(directory); - if (!lastDirectory.exists() || !managesDirectory(lastDirectory)) - return QString(); - for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) { - if (!managesDirectory(parentDir)) - return lastDirectory.absolutePath(); - } - return QString(); -} - SubversionControl *SubversionPlugin::subVersionControl() const { return static_cast<SubversionControl *>(versionControl()); diff --git a/src/plugins/subversion/subversionplugin.h b/src/plugins/subversion/subversionplugin.h index a7bb187c56d..278cb2d3033 100644 --- a/src/plugins/subversion/subversionplugin.h +++ b/src/plugins/subversion/subversionplugin.h @@ -95,8 +95,7 @@ public: bool vcsAdd15(const QString &workingDir, const QString &fileName); bool vcsDelete(const QString &workingDir, const QString &fileName); bool vcsMove(const QString &workingDir, const QString &from, const QString &to); - bool managesDirectory(const QString &directory) const; - QString findTopLevelForDirectory(const QString &directory) const; + bool managesDirectory(const QString &directory, QString *topLevel = 0) const; static SubversionPlugin *subversionPluginInstance(); @@ -145,8 +144,7 @@ private: bool enableAnnotationContextMenu = false); void svnStatus(const QString &workingDir, const QStringList &relativePath = QStringList()); void svnUpdate(const QString &workingDir, const QStringList &relativePaths = QStringList()); - bool managesDirectory(const QDir &directory) const; - QString findTopLevelForDirectoryI(const QString &directory) const; + bool checkSVNSubDir(const QDir &directory) const; void startCommit(const QString &workingDir, const QStringList &files = QStringList()); bool commit(const QString &messageFile, const QStringList &subVersionFileList); void cleanCommitMessageFile(); diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index 67b3e80901b..815a0622475 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -821,8 +821,8 @@ QString VCSBaseEditor::findDiffFile(const QString &f, Core::IVersionControl *con // Try to locate via repository. if (!control) return QString(); - const QString topLevel = control->findTopLevelForDirectory(sourceDir); - if (topLevel.isEmpty()) + QString topLevel; + if (!control->managesDirectory(sourceDir, &topLevel)) return QString(); const QFileInfo topLevelFileInfo(topLevel + slash + f); if (topLevelFileInfo.isFile()) -- GitLab