Mercurial > hg > easyhg
changeset 586:687d9e700e81 fswatcher
Check file timestamps for tracked files when a directory change is notified from FSEvents
author | Chris Cannam |
---|---|
date | Wed, 14 Mar 2012 11:40:58 +0000 |
parents | fa242885a233 |
children | 4ed384ea7f39 |
files | src/fswatcher.cpp src/fswatcher.h |
diffstat | 2 files changed, 70 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/src/fswatcher.cpp Tue Mar 13 17:58:17 2012 +0000 +++ b/src/fswatcher.cpp Wed Mar 14 11:40:58 2012 +0000 @@ -78,8 +78,10 @@ * whatever the fd ulimit is set to, but that's the default) and it * doesn't notify if a file within a directory is modified unless the * metadata changes. The main limitation of FSEvents is that it only - * notifies with directory granularity, but that's OK for us so long - * as notifications are actually provoked by file changes as well. + * notifies with directory granularity, but that might be OK for us so + * long as notifications are actually provoked by file changes as + * well. (In OS/X 10.7 there appear to be file-level notifications + * too, but that doesn't help us.) * * One other problem with FSEvents is that the API only exists on OS/X * 10.5 or newer -- on older versions we would have no option but to @@ -152,6 +154,7 @@ FsWatcher *watcher = reinterpret_cast<FsWatcher *>(clientCallBackInfo); const char *const *cpaths = reinterpret_cast<const char *const *>(paths); for (size_t i = 0; i < numEvents; ++i) { + std::cerr << "path " << i << " = " << cpaths[i] << std::endl; watcher->fsDirectoryChanged(QString::fromLocal8Bit(cpaths[i])); } } @@ -227,11 +230,18 @@ FsWatcher::setTrackedFilePaths(QStringList paths) { #ifdef Q_OS_MAC - // We don't need to do anything here, so long as addWorkDirectory - // has been called -- FSEvents monitors files within directories - // as well as the directories themselves (even though it only - // notifies with directory granularity) + + // FSEvents will notify when any file in the directory changes, + // but we need to be able to check whether the file change was + // meaningful to us if it didn't result in any files being added + // or removed -- and we have to do that by examining timestamps on + // the files we care about + foreach (QString p, paths) { + m_trackedFileUpdates[p] = QDateTime::currentDateTime(); + } + #else + QMutexLocker locker(&m_mutex); QSet<QString> alreadyWatched = @@ -253,6 +263,7 @@ } debugPrint(); + #endif } @@ -298,29 +309,40 @@ void FsWatcher::fsDirectoryChanged(QString path) { + bool haveChanges = false; + { QMutexLocker locker(&m_mutex); if (shouldIgnore(path)) return; QSet<QString> files = scanDirectory(path); + if (files == m_dirContents[path]) { + #ifdef DEBUG_FSWATCHER std::cerr << "FsWatcher: Directory " << path << " has changed, but not in a way that we are monitoring" << std::endl; #endif - return; + +#ifdef Q_OS_MAC + haveChanges = manuallyCheckTrackedFiles(); +#endif + } else { + #ifdef DEBUG_FSWATCHER std::cerr << "FsWatcher: Directory " << path << " has changed" << std::endl; #endif m_dirContents[path] = files; + size_t counter = ++m_lastCounter; + m_changes[path] = counter; + haveChanges = true; } - - size_t counter = ++m_lastCounter; - m_changes[path] = counter; } - emit changed(); + if (haveChanges) { + emit changed(); + } } void @@ -332,7 +354,7 @@ // We don't check whether the file matches an ignore pattern, // because we are only notified for file changes if we are // watching the file explicitly, i.e. the file is in the - // tracked file paths list. So we never want to ignore them + // tracked file paths list. So we never want to ignore these #ifdef DEBUG_FSWATCHER std::cerr << "FsWatcher: Tracked file " << path << " has changed" << std::endl; @@ -345,6 +367,38 @@ emit changed(); } +#ifdef Q_OS_MAC +bool +FsWatcher::manuallyCheckTrackedFiles() +{ + bool foundChanges = false; + + for (PathTimeMap::iterator i = m_trackedFileUpdates.begin(); + i != m_trackedFileUpdates.end(); ++i) { + + QString path = i.key(); + QDateTime prevUpdate = i.value(); + + QFileInfo fi(path); + QDateTime currUpdate = fi.lastModified(); + + if (currUpdate > prevUpdate) { + +#ifdef DEBUG_FSWATCHER + std::cerr << "FsWatcher: Tracked file " << path << " has been changed since last check" << std::endl; +#endif + i.value() = currUpdate; + + size_t counter = ++m_lastCounter; + m_changes[path] = counter; + foundChanges = true; + } + } + + return foundChanges; +} +#endif + bool FsWatcher::shouldIgnore(QString path) { @@ -383,8 +437,6 @@ files.insert(entry); } } -// std::cerr << "scanDirectory:" << std::endl; -// foreach (QString f, files) std::cerr << f << std::endl; return files; }
--- a/src/fswatcher.h Tue Mar 13 17:58:17 2012 +0000 +++ b/src/fswatcher.h Wed Mar 14 11:40:58 2012 +0000 @@ -24,6 +24,7 @@ #include <QSet> #include <QHash> #include <QMap> +#include <QDateTime> #include <QStringList> #ifndef Q_OS_MAC @@ -153,6 +154,9 @@ #ifdef Q_OS_MAC void *m_stream; + typedef QMap<QString, QDateTime> PathTimeMap; + PathTimeMap m_trackedFileUpdates; + bool manuallyCheckTrackedFiles(); #else QFileSystemWatcher m_watcher; #endif