2019-06-20 18:34:02 +02:00
|
|
|
/****************************************************************************
|
2017-01-30 11:24:46 +01:00
|
|
|
**
|
|
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
|
|
|
**
|
|
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include "clangpathwatcherinterface.h"
|
|
|
|
|
#include "clangpathwatchernotifier.h"
|
2019-06-06 10:57:55 +02:00
|
|
|
#include "directorypathcompressor.h"
|
2017-10-25 17:51:39 +02:00
|
|
|
#include "filepathcachinginterface.h"
|
2019-06-06 10:57:55 +02:00
|
|
|
#include "filesystem.h"
|
2017-10-25 17:51:39 +02:00
|
|
|
#include "stringcache.h"
|
2017-01-30 11:24:46 +01:00
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
#include <utils/algorithm.h>
|
|
|
|
|
|
2017-01-31 11:14:54 +01:00
|
|
|
#include <QTimer>
|
2017-01-30 11:24:46 +01:00
|
|
|
|
|
|
|
|
namespace ClangBackEnd {
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
template<class InputIt1, class InputIt2, class Callable>
|
|
|
|
|
void set_greedy_intersection_call(
|
|
|
|
|
InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable callable)
|
|
|
|
|
{
|
|
|
|
|
while (first1 != last1 && first2 != last2) {
|
|
|
|
|
if (*first1 < *first2) {
|
|
|
|
|
++first1;
|
|
|
|
|
} else {
|
|
|
|
|
if (*first2 < *first1)
|
|
|
|
|
++first2;
|
|
|
|
|
else
|
|
|
|
|
callable(*first1++);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-30 11:24:46 +01:00
|
|
|
class WatcherEntry
|
|
|
|
|
{
|
|
|
|
|
public:
|
2019-06-20 18:34:02 +02:00
|
|
|
ProjectChunkId id;
|
2019-06-06 10:57:55 +02:00
|
|
|
DirectoryPathId directoryPathId;
|
|
|
|
|
FilePathId filePathId;
|
|
|
|
|
long long lastModified = -1;
|
2017-01-30 11:24:46 +01:00
|
|
|
|
2017-12-14 11:37:19 +01:00
|
|
|
friend bool operator==(WatcherEntry first, WatcherEntry second)
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2019-06-06 10:57:55 +02:00
|
|
|
return first.id == second.id && first.directoryPathId == second.directoryPathId
|
|
|
|
|
&& first.filePathId == second.filePathId;
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
2017-12-14 11:37:19 +01:00
|
|
|
friend bool operator<(WatcherEntry first, WatcherEntry second)
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2019-06-06 10:57:55 +02:00
|
|
|
return std::tie(first.directoryPathId, first.filePathId, first.id)
|
|
|
|
|
< std::tie(second.directoryPathId, second.filePathId, second.id);
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
friend bool operator<(DirectoryPathId directoryPathId, WatcherEntry entry)
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2019-06-06 10:57:55 +02:00
|
|
|
return directoryPathId < entry.directoryPathId;
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
friend bool operator<(WatcherEntry entry, DirectoryPathId directoryPathId)
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2019-06-06 10:57:55 +02:00
|
|
|
return entry.directoryPathId < directoryPathId;
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
2017-12-14 11:37:19 +01:00
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
operator FilePathId() const { return filePathId; }
|
|
|
|
|
|
|
|
|
|
operator DirectoryPathId() const { return directoryPathId; }
|
2017-01-30 11:24:46 +01:00
|
|
|
};
|
|
|
|
|
|
2017-01-31 11:14:54 +01:00
|
|
|
using WatcherEntries = std::vector<WatcherEntry>;
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
template<typename FileSystemWatcher, typename Timer>
|
2018-01-17 17:06:13 +02:00
|
|
|
class CLANGSUPPORT_GCCEXPORT ClangPathWatcher : public ClangPathWatcherInterface
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
|
|
|
|
public:
|
2017-09-21 11:43:59 +02:00
|
|
|
ClangPathWatcher(FilePathCachingInterface &pathCache,
|
2019-06-06 10:57:55 +02:00
|
|
|
FileSystemInterface &fileSystem,
|
|
|
|
|
ClangPathWatcherNotifier *notifier = nullptr)
|
2019-07-02 14:15:33 +02:00
|
|
|
: m_fileStatusCache(fileSystem)
|
2019-06-06 10:57:55 +02:00
|
|
|
, m_fileSystem(fileSystem)
|
2019-07-02 14:15:33 +02:00
|
|
|
, m_pathCache(pathCache)
|
2019-06-06 10:57:55 +02:00
|
|
|
, m_notifier(notifier)
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
|
|
|
|
QObject::connect(&m_fileSystemWatcher,
|
2019-06-06 10:57:55 +02:00
|
|
|
&FileSystemWatcher::directoryChanged,
|
|
|
|
|
[&](const QString &path) { compressChangedDirectoryPath(path); });
|
2017-01-31 11:14:54 +01:00
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
m_directoryPathCompressor.setCallback([&](ClangBackEnd::DirectoryPathIds &&directoryPathIds) {
|
|
|
|
|
addChangedPathForFilePath(std::move(directoryPathIds));
|
2017-01-31 11:14:54 +01:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~ClangPathWatcher()
|
|
|
|
|
{
|
2019-06-06 10:57:55 +02:00
|
|
|
m_directoryPathCompressor.setCallback([&](DirectoryPathIds &&) {});
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void updateIdPaths(const std::vector<IdPaths> &idPaths) override
|
|
|
|
|
{
|
|
|
|
|
auto entriesAndIds = convertIdPathsToWatcherEntriesAndIds(idPaths);
|
|
|
|
|
|
|
|
|
|
addEntries(entriesAndIds.first);
|
|
|
|
|
removeUnusedEntries(entriesAndIds.first, entriesAndIds.second);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-13 15:09:30 +01:00
|
|
|
void removeIds(const ProjectPartIds &ids) override
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2019-03-13 15:09:30 +01:00
|
|
|
auto removedEntries = removeIdsFromWatchedEntries(ids);
|
2017-01-30 11:24:46 +01:00
|
|
|
|
|
|
|
|
auto filteredPaths = filterNotWatchedPaths(removedEntries);
|
|
|
|
|
|
|
|
|
|
if (!filteredPaths.empty())
|
2019-06-06 10:57:55 +02:00
|
|
|
m_fileSystemWatcher.removePaths(convertWatcherEntriesToDirectoryPathList(filteredPaths));
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setNotifier(ClangPathWatcherNotifier *notifier) override
|
|
|
|
|
{
|
|
|
|
|
m_notifier = notifier;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::size_t sizeOfIdPaths(const std::vector<IdPaths> &idPaths)
|
|
|
|
|
{
|
|
|
|
|
auto sumSize = [] (std::size_t size, const IdPaths &idPath) {
|
2017-09-21 11:43:59 +02:00
|
|
|
return size + idPath.filePathIds.size();
|
2017-01-30 11:24:46 +01:00
|
|
|
};
|
|
|
|
|
|
2017-04-26 11:47:38 +03:00
|
|
|
return std::accumulate(idPaths.begin(), idPaths.end(), std::size_t(0), sumSize);
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-20 18:34:02 +02:00
|
|
|
std::pair<WatcherEntries, ProjectChunkIds> convertIdPathsToWatcherEntriesAndIds(
|
2019-03-13 15:09:30 +01:00
|
|
|
const std::vector<IdPaths> &idPaths)
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2017-01-31 11:14:54 +01:00
|
|
|
WatcherEntries entries;
|
2017-01-30 11:24:46 +01:00
|
|
|
entries.reserve(sizeOfIdPaths(idPaths));
|
2019-06-20 18:34:02 +02:00
|
|
|
ProjectChunkIds ids;
|
2017-01-30 11:24:46 +01:00
|
|
|
ids.reserve(ids.size());
|
|
|
|
|
|
|
|
|
|
auto outputIterator = std::back_inserter(entries);
|
|
|
|
|
|
|
|
|
|
for (const IdPaths &idPath : idPaths)
|
|
|
|
|
{
|
2019-06-20 18:34:02 +02:00
|
|
|
ProjectChunkId id = idPath.id;
|
2017-01-30 11:24:46 +01:00
|
|
|
|
|
|
|
|
ids.push_back(id);
|
|
|
|
|
|
2017-09-21 11:43:59 +02:00
|
|
|
outputIterator = std::transform(idPath.filePathIds.begin(),
|
|
|
|
|
idPath.filePathIds.end(),
|
2017-01-30 11:24:46 +01:00
|
|
|
outputIterator,
|
2019-06-06 10:57:55 +02:00
|
|
|
[&](FilePathId filePathId) {
|
|
|
|
|
return WatcherEntry{
|
|
|
|
|
id,
|
|
|
|
|
m_pathCache.directoryPathId(filePathId),
|
|
|
|
|
filePathId,
|
|
|
|
|
m_fileStatusCache.lastModifiedTime(filePathId)};
|
|
|
|
|
});
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::sort(entries.begin(), entries.end());
|
|
|
|
|
std::sort(ids.begin(), ids.end());
|
|
|
|
|
|
|
|
|
|
return {entries, ids};
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-31 11:14:54 +01:00
|
|
|
void addEntries(const WatcherEntries &entries)
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
|
|
|
|
auto newEntries = notWatchedEntries(entries);
|
|
|
|
|
|
|
|
|
|
auto filteredPaths = filterNotWatchedPaths(newEntries);
|
|
|
|
|
|
|
|
|
|
mergeToWatchedEntries(newEntries);
|
|
|
|
|
|
|
|
|
|
if (!filteredPaths.empty())
|
2019-06-06 10:57:55 +02:00
|
|
|
m_fileSystemWatcher.addPaths(convertWatcherEntriesToDirectoryPathList(filteredPaths));
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-20 18:34:02 +02:00
|
|
|
void removeUnusedEntries(const WatcherEntries &entries, const ProjectChunkIds &ids)
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
|
|
|
|
auto oldEntries = notAnymoreWatchedEntriesWithIds(entries, ids);
|
|
|
|
|
|
|
|
|
|
removeFromWatchedEntries(oldEntries);
|
|
|
|
|
|
|
|
|
|
auto filteredPaths = filterNotWatchedPaths(oldEntries);
|
|
|
|
|
|
|
|
|
|
if (!filteredPaths.empty())
|
2019-06-06 10:57:55 +02:00
|
|
|
m_fileSystemWatcher.removePaths(convertWatcherEntriesToDirectoryPathList(filteredPaths));
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
FileSystemWatcher &fileSystemWatcher() { return m_fileSystemWatcher; }
|
|
|
|
|
|
|
|
|
|
QStringList convertWatcherEntriesToDirectoryPathList(const DirectoryPathIds &directoryPathIds) const
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2019-06-06 10:57:55 +02:00
|
|
|
return Utils::transform<QStringList>(directoryPathIds, [&](DirectoryPathId id) {
|
|
|
|
|
return QString(m_pathCache.directoryPath(id));
|
|
|
|
|
});
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
QStringList convertWatcherEntriesToDirectoryPathList(const WatcherEntries &watcherEntries) const
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2019-06-06 10:57:55 +02:00
|
|
|
DirectoryPathIds directoryPathIds = Utils::transform<DirectoryPathIds>(
|
|
|
|
|
watcherEntries, [&](WatcherEntry entry) { return entry.directoryPathId; });
|
2017-01-30 11:24:46 +01:00
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
std::sort(directoryPathIds.begin(), directoryPathIds.end());
|
|
|
|
|
directoryPathIds.erase(std::unique(directoryPathIds.begin(), directoryPathIds.end()),
|
|
|
|
|
directoryPathIds.end());
|
2017-01-30 11:24:46 +01:00
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
return convertWatcherEntriesToDirectoryPathList(directoryPathIds);
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
WatcherEntries notWatchedEntries(const WatcherEntries &entries) const
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2017-01-31 11:14:54 +01:00
|
|
|
WatcherEntries notWatchedEntries;
|
2017-01-30 11:24:46 +01:00
|
|
|
notWatchedEntries.reserve(entries.size());
|
|
|
|
|
|
|
|
|
|
std::set_difference(entries.begin(),
|
|
|
|
|
entries.end(),
|
|
|
|
|
m_watchedEntries.cbegin(),
|
|
|
|
|
m_watchedEntries.cend(),
|
2019-06-06 10:57:55 +02:00
|
|
|
std::back_inserter(notWatchedEntries));
|
2017-01-30 11:24:46 +01:00
|
|
|
|
|
|
|
|
return notWatchedEntries;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
DirectoryPathIds notWatchedPaths(const DirectoryPathIds &ids) const
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2019-06-06 10:57:55 +02:00
|
|
|
DirectoryPathIds notWatchedDirectoryIds;
|
|
|
|
|
notWatchedDirectoryIds.reserve(ids.size());
|
2017-01-30 11:24:46 +01:00
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
std::set_difference(ids.begin(),
|
|
|
|
|
ids.end(),
|
|
|
|
|
m_watchedEntries.cbegin(),
|
|
|
|
|
m_watchedEntries.cend(),
|
|
|
|
|
std::back_inserter(notWatchedDirectoryIds));
|
2017-01-30 11:24:46 +01:00
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
return notWatchedDirectoryIds;
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename Compare>
|
2017-01-31 11:14:54 +01:00
|
|
|
WatcherEntries notAnymoreWatchedEntries(
|
|
|
|
|
const WatcherEntries &newEntries,
|
2017-01-30 11:24:46 +01:00
|
|
|
Compare compare) const
|
|
|
|
|
{
|
2017-01-31 11:14:54 +01:00
|
|
|
WatcherEntries notAnymoreWatchedEntries;
|
2017-01-30 11:24:46 +01:00
|
|
|
notAnymoreWatchedEntries.reserve(m_watchedEntries.size());
|
|
|
|
|
|
|
|
|
|
std::set_difference(m_watchedEntries.cbegin(),
|
|
|
|
|
m_watchedEntries.cend(),
|
|
|
|
|
newEntries.begin(),
|
|
|
|
|
newEntries.end(),
|
|
|
|
|
std::back_inserter(notAnymoreWatchedEntries),
|
|
|
|
|
compare);
|
|
|
|
|
|
|
|
|
|
return notAnymoreWatchedEntries;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-13 15:09:30 +01:00
|
|
|
WatcherEntries notAnymoreWatchedEntriesWithIds(const WatcherEntries &newEntries,
|
2019-06-20 18:34:02 +02:00
|
|
|
const ProjectChunkIds &ids) const
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
|
|
|
|
auto oldEntries = notAnymoreWatchedEntries(newEntries, std::less<WatcherEntry>());
|
|
|
|
|
|
|
|
|
|
auto newEnd = std::remove_if(oldEntries.begin(),
|
|
|
|
|
oldEntries.end(),
|
|
|
|
|
[&] (WatcherEntry entry) {
|
|
|
|
|
return !std::binary_search(ids.begin(), ids.end(), entry.id);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
oldEntries.erase(newEnd, oldEntries.end());
|
|
|
|
|
|
|
|
|
|
return oldEntries;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-31 11:14:54 +01:00
|
|
|
void mergeToWatchedEntries(const WatcherEntries &newEntries)
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2017-01-31 11:14:54 +01:00
|
|
|
WatcherEntries newWatchedEntries;
|
2017-01-30 11:24:46 +01:00
|
|
|
newWatchedEntries.reserve(m_watchedEntries.size() + newEntries.size());
|
|
|
|
|
|
|
|
|
|
std::merge(m_watchedEntries.cbegin(),
|
|
|
|
|
m_watchedEntries.cend(),
|
|
|
|
|
newEntries.begin(),
|
|
|
|
|
newEntries.end(),
|
|
|
|
|
std::back_inserter(newWatchedEntries));
|
|
|
|
|
|
|
|
|
|
m_watchedEntries = std::move(newWatchedEntries);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
static DirectoryPathIds uniquePaths(const WatcherEntries &pathEntries)
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2019-06-06 10:57:55 +02:00
|
|
|
DirectoryPathIds uniqueDirectoryIds;
|
|
|
|
|
uniqueDirectoryIds.reserve(pathEntries.size());
|
2017-01-30 11:24:46 +01:00
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
auto compare = [](WatcherEntry first, WatcherEntry second) {
|
|
|
|
|
return first.directoryPathId == second.directoryPathId;
|
2017-01-30 11:24:46 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::unique_copy(pathEntries.begin(),
|
|
|
|
|
pathEntries.end(),
|
2019-06-06 10:57:55 +02:00
|
|
|
std::back_inserter(uniqueDirectoryIds),
|
2017-01-30 11:24:46 +01:00
|
|
|
compare);
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
return uniqueDirectoryIds;
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
DirectoryPathIds filterNotWatchedPaths(const WatcherEntries &entries) const
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
|
|
|
|
return notWatchedPaths(uniquePaths(entries));
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-31 11:14:54 +01:00
|
|
|
const WatcherEntries &watchedEntries() const
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
|
|
|
|
return m_watchedEntries;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-13 15:09:30 +01:00
|
|
|
WatcherEntries removeIdsFromWatchedEntries(const ProjectPartIds &ids)
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2019-03-13 15:09:30 +01:00
|
|
|
auto keep = [&](WatcherEntry entry) {
|
2017-01-30 11:24:46 +01:00
|
|
|
return !std::binary_search(ids.begin(), ids.end(), entry.id);
|
|
|
|
|
};
|
|
|
|
|
|
2019-03-13 15:09:30 +01:00
|
|
|
auto found = std::stable_partition(m_watchedEntries.begin(), m_watchedEntries.end(), keep);
|
2017-01-30 11:24:46 +01:00
|
|
|
|
2017-01-31 11:14:54 +01:00
|
|
|
WatcherEntries removedEntries(found, m_watchedEntries.end());
|
2017-01-30 11:24:46 +01:00
|
|
|
|
|
|
|
|
m_watchedEntries.erase(found, m_watchedEntries.end());
|
|
|
|
|
|
|
|
|
|
return removedEntries;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-31 11:14:54 +01:00
|
|
|
void removeFromWatchedEntries(const WatcherEntries &oldEntries)
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2017-01-31 11:14:54 +01:00
|
|
|
WatcherEntries newWatchedEntries;
|
2017-01-30 11:24:46 +01:00
|
|
|
newWatchedEntries.reserve(m_watchedEntries.size() - oldEntries.size());
|
|
|
|
|
|
|
|
|
|
std::set_difference(m_watchedEntries.cbegin(),
|
|
|
|
|
m_watchedEntries.cend(),
|
|
|
|
|
oldEntries.begin(),
|
|
|
|
|
oldEntries.end(),
|
|
|
|
|
std::back_inserter(newWatchedEntries));
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
m_watchedEntries = std::move(newWatchedEntries);
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
void compressChangedDirectoryPath(const QString &path)
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
2019-06-06 10:57:55 +02:00
|
|
|
m_directoryPathCompressor.addDirectoryPathId(
|
|
|
|
|
m_pathCache.directoryPathId(Utils::PathString{path}));
|
2017-01-31 11:14:54 +01:00
|
|
|
}
|
2017-01-30 11:24:46 +01:00
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
WatcherEntries watchedEntriesForPaths(ClangBackEnd::DirectoryPathIds &&directoryPathIds)
|
2017-01-31 11:14:54 +01:00
|
|
|
{
|
|
|
|
|
WatcherEntries foundEntries;
|
2019-06-06 10:57:55 +02:00
|
|
|
foundEntries.reserve(m_watchedEntries.size());
|
|
|
|
|
|
|
|
|
|
set_greedy_intersection_call(m_watchedEntries.begin(),
|
|
|
|
|
m_watchedEntries.end(),
|
|
|
|
|
directoryPathIds.begin(),
|
|
|
|
|
directoryPathIds.end(),
|
|
|
|
|
[&](WatcherEntry &entry) {
|
|
|
|
|
m_fileStatusCache.update(entry.filePathId);
|
|
|
|
|
auto currentLastModified = m_fileStatusCache.lastModifiedTime(
|
|
|
|
|
entry.filePathId);
|
|
|
|
|
if (entry.lastModified < currentLastModified) {
|
|
|
|
|
foundEntries.push_back(entry);
|
|
|
|
|
entry.lastModified = currentLastModified;
|
|
|
|
|
}
|
|
|
|
|
});
|
2017-01-31 11:14:54 +01:00
|
|
|
|
|
|
|
|
return foundEntries;
|
|
|
|
|
}
|
2017-01-30 11:24:46 +01:00
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
FilePathIds watchedPaths(const WatcherEntries &entries) const
|
2017-12-14 11:37:19 +01:00
|
|
|
{
|
2019-06-06 10:57:55 +02:00
|
|
|
auto filePathIds = Utils::transform<FilePathIds>(entries, [](WatcherEntry entry) {
|
|
|
|
|
return entry.filePathId;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
std::sort(filePathIds.begin(), filePathIds.end());
|
2017-12-14 11:37:19 +01:00
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
filePathIds.erase(std::unique(filePathIds.begin(), filePathIds.end()), filePathIds.end());
|
2017-12-14 11:37:19 +01:00
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
return filePathIds;
|
2017-12-14 11:37:19 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-20 18:34:02 +02:00
|
|
|
std::vector<IdPaths> idPathsForWatcherEntries(WatcherEntries &&foundEntries)
|
2017-01-31 11:14:54 +01:00
|
|
|
{
|
2019-06-20 18:34:02 +02:00
|
|
|
std::sort(foundEntries.begin(), foundEntries.end(), [](WatcherEntry first, WatcherEntry second) {
|
|
|
|
|
return std::tie(first.id, first.filePathId) < std::tie(second.id, second.filePathId);
|
|
|
|
|
});
|
2017-01-30 11:24:46 +01:00
|
|
|
|
2019-06-20 18:34:02 +02:00
|
|
|
std::vector<IdPaths> idPaths;
|
|
|
|
|
idPaths.reserve(foundEntries.size());
|
2017-01-31 11:14:54 +01:00
|
|
|
|
2019-06-20 18:34:02 +02:00
|
|
|
for (WatcherEntry entry : foundEntries) {
|
|
|
|
|
if (idPaths.empty() || idPaths.back().id != entry.id)
|
|
|
|
|
idPaths.push_back({entry.id, {}});
|
|
|
|
|
idPaths.back().filePathIds.push_back(entry.filePathId);
|
|
|
|
|
}
|
2017-01-30 11:24:46 +01:00
|
|
|
|
2019-06-20 18:34:02 +02:00
|
|
|
return idPaths;
|
2017-01-31 11:14:54 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-06 10:57:55 +02:00
|
|
|
void addChangedPathForFilePath(DirectoryPathIds &&directoryPathIds)
|
2017-01-31 11:14:54 +01:00
|
|
|
{
|
|
|
|
|
if (m_notifier) {
|
2019-06-06 10:57:55 +02:00
|
|
|
WatcherEntries foundEntries = watchedEntriesForPaths(std::move(directoryPathIds));
|
2017-01-31 11:14:54 +01:00
|
|
|
|
2019-06-20 18:34:02 +02:00
|
|
|
FilePathIds watchedFilePathIds = watchedPaths(foundEntries);
|
|
|
|
|
|
|
|
|
|
std::vector<IdPaths> changedIdPaths = idPathsForWatcherEntries(std::move(foundEntries));
|
2017-01-31 11:14:54 +01:00
|
|
|
|
2019-06-20 18:34:02 +02:00
|
|
|
m_notifier->pathsChanged(watchedFilePathIds);
|
|
|
|
|
m_notifier->pathsWithIdsChanged(changedIdPaths);
|
2017-01-31 11:14:54 +01:00
|
|
|
}
|
2017-01-30 11:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
2017-09-21 11:43:59 +02:00
|
|
|
FilePathCachingInterface &pathCache()
|
2017-01-30 11:24:46 +01:00
|
|
|
{
|
|
|
|
|
return m_pathCache;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2017-01-31 11:14:54 +01:00
|
|
|
WatcherEntries m_watchedEntries;
|
2017-01-30 11:24:46 +01:00
|
|
|
FileSystemWatcher m_fileSystemWatcher;
|
2019-06-06 10:57:55 +02:00
|
|
|
FileStatusCache m_fileStatusCache;
|
|
|
|
|
FileSystemInterface &m_fileSystem;
|
2017-09-21 11:43:59 +02:00
|
|
|
FilePathCachingInterface &m_pathCache;
|
2017-01-30 11:24:46 +01:00
|
|
|
ClangPathWatcherNotifier *m_notifier;
|
2019-06-06 10:57:55 +02:00
|
|
|
DirectoryPathCompressor<Timer> m_directoryPathCompressor;
|
2017-01-30 11:24:46 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace ClangBackEnd
|