annotate src/fswatcher.cpp @ 539:3935a7e621ca fswatcher

Add setTrackedFilePaths, and comments
author Chris Cannam
date Fri, 10 Feb 2012 21:49:27 +0000
parents bdc9de794839
children fc2df97920e8
rev   line source
Chris@538 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@538 2
Chris@538 3 /*
Chris@538 4 EasyMercurial
Chris@538 5
Chris@538 6 Based on hgExplorer by Jari Korhonen
Chris@538 7 Copyright (c) 2010 Jari Korhonen
Chris@538 8 Copyright (c) 2011 Chris Cannam
Chris@538 9 Copyright (c) 2011 Queen Mary, University of London
Chris@538 10
Chris@538 11 This program is free software; you can redistribute it and/or
Chris@538 12 modify it under the terms of the GNU General Public License as
Chris@538 13 published by the Free Software Foundation; either version 2 of the
Chris@538 14 License, or (at your option) any later version. See the file
Chris@538 15 COPYING included with this distribution for more information.
Chris@538 16 */
Chris@538 17
Chris@538 18 #include "fswatcher.h"
Chris@538 19
Chris@538 20 #include <QMutexLocker>
Chris@538 21 #include <QDir>
Chris@538 22
Chris@538 23 #include <deque>
Chris@538 24
Chris@539 25 /*
Chris@539 26 * Watching the filesystem is trickier than it seems at first glance.
Chris@539 27 *
Chris@539 28 * We ideally should watch every directory, and every file that is
Chris@539 29 * tracked by Hg. If a new file is created in a directory, then we
Chris@539 30 * need to respond in order to show it as a potential candidate to be
Chris@539 31 * added.
Chris@539 32 *
Chris@539 33 * Complicating matters though is that Hg itself might modify the
Chris@539 34 * filesystem. This can happen even in "read-only" operations: for
Chris@539 35 * example, hg stat creates files called hg-checklink and hg-checkexec
Chris@539 36 * to test properties of the filesystem. So we need to know to ignore
Chris@539 37 * those files; unfortunately, when watching a directory (which is how
Chris@539 38 * we find out about the creation of new files) we are notified only
Chris@539 39 * that the directory has changed -- we aren't told what changed. So
Chris@539 40 * we need to rescan the directory merely to find out whether to
Chris@539 41 * ignore the change or not.
Chris@539 42 */
Chris@539 43
Chris@538 44 FsWatcher::FsWatcher() :
Chris@538 45 m_lastToken(0),
Chris@538 46 m_lastCounter(0)
Chris@538 47 {
Chris@538 48 connect(&m_watcher, SIGNAL(directoryChanged(QString)),
Chris@538 49 this, SLOT(fsDirectoryChanged(QString)));
Chris@538 50 connect(&m_watcher, SIGNAL(fileChanged(QString)),
Chris@538 51 this, SLOT(fsFileChanged(QString)));
Chris@538 52 }
Chris@538 53
Chris@538 54 FsWatcher::~FsWatcher()
Chris@538 55 {
Chris@538 56 }
Chris@538 57
Chris@538 58 void
Chris@538 59 FsWatcher::setWorkDirPath(QString path)
Chris@538 60 {
Chris@538 61 QMutexLocker locker(&m_mutex);
Chris@538 62 m_watcher.removePaths(m_watcher.directories());
Chris@538 63 m_watcher.removePaths(m_watcher.files());
Chris@538 64 m_workDirPath = path;
Chris@538 65 addWorkDirectory(path);
Chris@538 66 }
Chris@538 67
Chris@538 68 void
Chris@539 69 FsWatcher::setTrackedFilePaths(QStringList paths)
Chris@539 70 {
Chris@539 71 QMutexLocker locker(&m_mutex);
Chris@539 72 m_watcher.removePaths(m_watcher.files());
Chris@539 73 foreach (QString path, paths) {
Chris@539 74 m_watcher.addPath(path);
Chris@539 75 }
Chris@539 76 }
Chris@539 77
Chris@539 78 void
Chris@538 79 FsWatcher::addWorkDirectory(QString path)
Chris@538 80 {
Chris@538 81 // QFileSystemWatcher will refuse to add a file or directory to
Chris@538 82 // its watch list that it is already watching -- fine -- but it
Chris@538 83 // prints a warning when this happens, which we wouldn't want. So
Chris@538 84 // we'll check for duplicates ourselves.
Chris@538 85 QSet<QString> alreadyWatched =
Chris@538 86 QSet<QString>::fromList(m_watcher.directories());
Chris@538 87
Chris@538 88 std::deque<QString> pending;
Chris@538 89 pending.push_back(path);
Chris@538 90
Chris@538 91 while (!pending.empty()) {
Chris@538 92
Chris@538 93 QString path = pending.front();
Chris@538 94 pending.pop_front();
Chris@538 95 if (!alreadyWatched.contains(path)) {
Chris@538 96 m_watcher.addPath(path);
Chris@538 97 }
Chris@538 98
Chris@538 99 QDir d(path);
Chris@538 100 if (d.exists()) {
Chris@538 101 d.setFilter(QDir::Dirs | QDir::NoDotAndDotDot |
Chris@538 102 QDir::Readable | QDir::NoSymLinks);
Chris@538 103 foreach (QString entry, d.entryList()) {
Chris@538 104 if (entry.startsWith('.')) continue;
Chris@538 105 QString entryPath = d.absoluteFilePath(entry);
Chris@538 106 pending.push_back(entryPath);
Chris@538 107 }
Chris@538 108 }
Chris@538 109 }
Chris@538 110 }
Chris@538 111
Chris@538 112 void
Chris@538 113 FsWatcher::setIgnoredFilePrefixes(QStringList prefixes)
Chris@538 114 {
Chris@538 115 QMutexLocker locker(&m_mutex);
Chris@538 116 m_ignoredPrefixes = prefixes;
Chris@538 117 }
Chris@538 118
Chris@538 119 void
Chris@538 120 FsWatcher::setIgnoredFileSuffixes(QStringList suffixes)
Chris@538 121 {
Chris@538 122 QMutexLocker locker(&m_mutex);
Chris@538 123 m_ignoredSuffixes = suffixes;
Chris@538 124 }
Chris@538 125
Chris@538 126 int
Chris@538 127 FsWatcher::getNewToken()
Chris@538 128 {
Chris@538 129 QMutexLocker locker(&m_mutex);
Chris@538 130 int token = ++m_lastToken;
Chris@538 131 m_tokenMap[token] = m_lastCounter;
Chris@538 132 return token;
Chris@538 133 }
Chris@538 134
Chris@538 135 QSet<QString>
Chris@538 136 FsWatcher::getChangedPaths(int token)
Chris@538 137 {
Chris@538 138 QMutexLocker locker(&m_mutex);
Chris@538 139 size_t lastUpdatedAt = m_tokenMap[token];
Chris@538 140 QSet<QString> changed;
Chris@538 141 for (QHash<QString, size_t>::const_iterator i = m_changes.begin();
Chris@538 142 i != m_changes.end(); ++i) {
Chris@538 143 if (i.value() > lastUpdatedAt) {
Chris@538 144 changed.insert(i.key());
Chris@538 145 }
Chris@538 146 }
Chris@538 147 m_tokenMap[token] = m_lastCounter;
Chris@538 148 return changed;
Chris@538 149 }
Chris@538 150
Chris@538 151 void
Chris@538 152 FsWatcher::fsDirectoryChanged(QString path)
Chris@538 153 {
Chris@538 154 {
Chris@538 155 QMutexLocker locker(&m_mutex);
Chris@538 156 if (shouldIgnore(path)) return;
Chris@538 157 size_t counter = ++m_lastCounter;
Chris@538 158 m_changes[path] = counter;
Chris@538 159 }
Chris@538 160 emit changed();
Chris@538 161 }
Chris@538 162
Chris@538 163 void
Chris@538 164 FsWatcher::fsFileChanged(QString path)
Chris@538 165 {
Chris@538 166 QMutexLocker locker(&m_mutex);
Chris@538 167 }
Chris@538 168
Chris@538 169 bool
Chris@538 170 FsWatcher::shouldIgnore(QString path)
Chris@538 171 {
Chris@538 172
Chris@538 173 }
Chris@538 174