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@644
|
8 Copyright (c) 2013 Chris Cannam
|
Chris@644
|
9 Copyright (c) 2013 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@584
|
18 #include <QMutexLocker>
|
Chris@584
|
19 #include <QDir>
|
Chris@584
|
20
|
Chris@584
|
21 #ifdef Q_OS_MAC
|
Chris@584
|
22 // Must include this before debug.h
|
Chris@584
|
23 #include <CoreServices/CoreServices.h>
|
Chris@584
|
24 #endif
|
Chris@584
|
25
|
Chris@538
|
26 #include "fswatcher.h"
|
Chris@540
|
27 #include "debug.h"
|
Chris@538
|
28
|
Chris@538
|
29 #include <deque>
|
Chris@538
|
30
|
Chris@603
|
31 //#define DEBUG_FSWATCHER 1
|
Chris@540
|
32
|
Chris@539
|
33 /*
|
Chris@539
|
34 * Watching the filesystem is trickier than it seems at first glance.
|
Chris@539
|
35 *
|
Chris@539
|
36 * We ideally should watch every directory, and every file that is
|
Chris@539
|
37 * tracked by Hg. If a new file is created in a directory, then we
|
Chris@539
|
38 * need to respond in order to show it as a potential candidate to be
|
Chris@539
|
39 * added.
|
Chris@539
|
40 *
|
Chris@539
|
41 * Complicating matters though is that Hg itself might modify the
|
Chris@539
|
42 * filesystem. This can happen even in "read-only" operations: for
|
Chris@539
|
43 * example, hg stat creates files called hg-checklink and hg-checkexec
|
Chris@539
|
44 * to test properties of the filesystem. So we need to know to ignore
|
Chris@539
|
45 * those files; unfortunately, when watching a directory (which is how
|
Chris@539
|
46 * we find out about the creation of new files) we are notified only
|
Chris@540
|
47 * that the directory has changed -- we aren't told what changed.
|
Chris@540
|
48 *
|
Chris@540
|
49 * This means that, when a directory changes, we need to rescan the
|
Chris@540
|
50 * directory to learn whether the set of files in it _excluding_ files
|
Chris@540
|
51 * matching our ignore patterns differs from the previous scan, and
|
Chris@540
|
52 * ignore the change if it doesn't.
|
Chris@584
|
53 *
|
Chris@584
|
54 */
|
Chris@584
|
55
|
Chris@584
|
56 /*
|
Chris@584
|
57 * 20120312 -- Another complication. The documentation for
|
Chris@584
|
58 * QFileSystemWatcher says:
|
Chris@584
|
59 *
|
Chris@584
|
60 * On Mac OS X 10.4 [...] an open file descriptor is required for
|
Chris@584
|
61 * each monitored file. [...] This means that addPath() and
|
Chris@584
|
62 * addPaths() will fail if your process tries to add more than 256
|
Chris@584
|
63 * files or directories to the file system monitor [...] Mac OS X
|
Chris@584
|
64 * 10.5 and up use a different backend and do not suffer from this
|
Chris@584
|
65 * issue.
|
Chris@584
|
66 *
|
Chris@584
|
67 * Unfortunately, the last sentence above is not true:
|
Chris@584
|
68 * http://qt.gitorious.org/qt/qt/commit/6d1baf9979346d6f15da81a535becb4046278962
|
Chris@584
|
69 * ("Removing the usage of FSEvents-based backend for now as it has a
|
Chris@584
|
70 * few bugs..."). It can't be restored without hacking the Qt source,
|
Chris@584
|
71 * which we don't want to do in this context. The commit log doesn't
|
Chris@584
|
72 * make clear how serious the bugs were -- an example is given but it
|
Chris@584
|
73 * doesn't indicate whether it's an edge case or a common case and
|
Chris@584
|
74 * whether the result was a crash or failure to notify.
|
Chris@584
|
75 *
|
Chris@584
|
76 * This means the Qt class uses kqueue instead on OS/X, but that
|
Chris@584
|
77 * doesn't really work for us -- it can only monitor 256 files (or
|
Chris@584
|
78 * whatever the fd ulimit is set to, but that's the default) and it
|
Chris@584
|
79 * doesn't notify if a file within a directory is modified unless the
|
Chris@584
|
80 * metadata changes. The main limitation of FSEvents is that it only
|
Chris@586
|
81 * notifies with directory granularity, but that might be OK for us so
|
Chris@586
|
82 * long as notifications are actually provoked by file changes as
|
Chris@586
|
83 * well. (In OS/X 10.7 there appear to be file-level notifications
|
Chris@586
|
84 * too, but that doesn't help us.)
|
Chris@584
|
85 *
|
Chris@584
|
86 * One other problem with FSEvents is that the API only exists on OS/X
|
Chris@584
|
87 * 10.5 or newer -- on older versions we would have no option but to
|
Chris@584
|
88 * use kqueue via QFileSystemWatcher. But we can't ship a binary
|
Chris@584
|
89 * linked with the FSEvents API to run on 10.4 without some fiddling,
|
Chris@584
|
90 * and I'm not really keen to do that either. That may be our cue to
|
Chris@584
|
91 * drop 10.4 support for EasyMercurial.
|
Chris@539
|
92 */
|
Chris@539
|
93
|
Chris@730
|
94 static bool abandoning = false; // emergency flag for use by non-member callback
|
Chris@730
|
95
|
Chris@538
|
96 FsWatcher::FsWatcher() :
|
Chris@538
|
97 m_lastToken(0),
|
Chris@538
|
98 m_lastCounter(0)
|
Chris@538
|
99 {
|
Chris@584
|
100 #ifdef Q_OS_MAC
|
Chris@584
|
101 m_stream = 0; // create when we have a path
|
Chris@584
|
102 #else
|
Chris@538
|
103 connect(&m_watcher, SIGNAL(directoryChanged(QString)),
|
Chris@538
|
104 this, SLOT(fsDirectoryChanged(QString)));
|
Chris@538
|
105 connect(&m_watcher, SIGNAL(fileChanged(QString)),
|
Chris@538
|
106 this, SLOT(fsFileChanged(QString)));
|
Chris@584
|
107 #endif
|
Chris@538
|
108 }
|
Chris@538
|
109
|
Chris@538
|
110 FsWatcher::~FsWatcher()
|
Chris@538
|
111 {
|
Chris@730
|
112 QMutexLocker locker(&m_mutex);
|
Chris@730
|
113 abandoning = true;
|
Chris@538
|
114 }
|
Chris@538
|
115
|
Chris@538
|
116 void
|
Chris@538
|
117 FsWatcher::setWorkDirPath(QString path)
|
Chris@538
|
118 {
|
Chris@538
|
119 QMutexLocker locker(&m_mutex);
|
Chris@541
|
120 if (m_workDirPath == path) return;
|
Chris@584
|
121 clearWatchedPaths();
|
Chris@584
|
122 m_workDirPath = path;
|
Chris@584
|
123 addWorkDirectory(path);
|
Chris@584
|
124 debugPrint();
|
Chris@584
|
125 }
|
Chris@584
|
126
|
Chris@584
|
127 void
|
Chris@584
|
128 FsWatcher::clearWatchedPaths()
|
Chris@584
|
129 {
|
Chris@584
|
130 #ifdef Q_OS_MAC
|
Chris@584
|
131 FSEventStreamRef stream = (FSEventStreamRef)m_stream;
|
Chris@584
|
132 if (stream) {
|
Chris@584
|
133 FSEventStreamStop(stream);
|
Chris@584
|
134 FSEventStreamInvalidate(stream);
|
Chris@584
|
135 FSEventStreamRelease(stream);
|
Chris@584
|
136 }
|
Chris@584
|
137 m_stream = 0;
|
Chris@584
|
138 #else
|
Chris@562
|
139 // annoyingly, removePaths prints a warning if given an empty list
|
Chris@562
|
140 if (!m_watcher.directories().empty()) {
|
Chris@562
|
141 m_watcher.removePaths(m_watcher.directories());
|
Chris@562
|
142 }
|
Chris@562
|
143 if (!m_watcher.files().empty()) {
|
Chris@562
|
144 m_watcher.removePaths(m_watcher.files());
|
Chris@562
|
145 }
|
Chris@584
|
146 #endif
|
Chris@538
|
147 }
|
Chris@538
|
148
|
Chris@584
|
149 #ifdef Q_OS_MAC
|
Chris@584
|
150 static void
|
Chris@699
|
151 fsEventsCallback(ConstFSEventStreamRef /* streamRef */,
|
Chris@584
|
152 void *clientCallBackInfo,
|
Chris@585
|
153 size_t numEvents,
|
Chris@585
|
154 void *paths,
|
Chris@699
|
155 const FSEventStreamEventFlags /* eventFlags */[],
|
Chris@699
|
156 const FSEventStreamEventId /*eventIDs */[])
|
Chris@539
|
157 {
|
Chris@730
|
158 if (abandoning) return;
|
Chris@585
|
159 FsWatcher *watcher = reinterpret_cast<FsWatcher *>(clientCallBackInfo);
|
Chris@585
|
160 const char *const *cpaths = reinterpret_cast<const char *const *>(paths);
|
Chris@585
|
161 for (size_t i = 0; i < numEvents; ++i) {
|
Chris@647
|
162 #ifdef DEBUG_FSWATCHER
|
Chris@586
|
163 std::cerr << "path " << i << " = " << cpaths[i] << std::endl;
|
Chris@647
|
164 #endif
|
Chris@585
|
165 watcher->fsDirectoryChanged(QString::fromLocal8Bit(cpaths[i]));
|
Chris@585
|
166 }
|
Chris@539
|
167 }
|
Chris@584
|
168 #endif
|
Chris@539
|
169
|
Chris@539
|
170 void
|
Chris@538
|
171 FsWatcher::addWorkDirectory(QString path)
|
Chris@538
|
172 {
|
Chris@584
|
173 #ifdef Q_OS_MAC
|
Chris@585
|
174
|
Chris@585
|
175 CFStringRef cfPath = CFStringCreateWithCharacters
|
Chris@585
|
176 (0, reinterpret_cast<const UniChar *>(path.unicode()),
|
Chris@585
|
177 path.length());
|
Chris@585
|
178
|
Chris@585
|
179 CFArrayRef cfPaths = CFArrayCreate(0, (const void **)&cfPath, 1, 0);
|
Chris@585
|
180
|
Chris@585
|
181 FSEventStreamContext ctx = { 0, 0, 0, 0, 0 };
|
Chris@585
|
182 ctx.info = this;
|
Chris@585
|
183
|
Chris@584
|
184 FSEventStreamRef stream =
|
Chris@584
|
185 FSEventStreamCreate(kCFAllocatorDefault,
|
Chris@585
|
186 &fsEventsCallback,
|
Chris@585
|
187 &ctx,
|
Chris@584
|
188 cfPaths,
|
Chris@584
|
189 kFSEventStreamEventIdSinceNow,
|
Chris@584
|
190 1.0, // latency, seconds
|
Chris@584
|
191 kFSEventStreamCreateFlagNone);
|
Chris@584
|
192
|
Chris@584
|
193 m_stream = stream;
|
Chris@584
|
194
|
Chris@584
|
195 FSEventStreamScheduleWithRunLoop(stream,
|
Chris@584
|
196 CFRunLoopGetCurrent(),
|
Chris@584
|
197 kCFRunLoopDefaultMode);
|
Chris@584
|
198
|
Chris@584
|
199 if (!FSEventStreamStart(stream)) {
|
Chris@584
|
200 std::cerr << "ERROR: FsWatcher::addWorkDirectory: Failed to start FSEvent stream" << std::endl;
|
Chris@584
|
201 }
|
Chris@584
|
202 #else
|
Chris@538
|
203 // QFileSystemWatcher will refuse to add a file or directory to
|
Chris@538
|
204 // its watch list that it is already watching -- fine -- but it
|
Chris@538
|
205 // prints a warning when this happens, which we wouldn't want. So
|
Chris@538
|
206 // we'll check for duplicates ourselves.
|
Chris@538
|
207 QSet<QString> alreadyWatched =
|
Chris@538
|
208 QSet<QString>::fromList(m_watcher.directories());
|
Chris@538
|
209
|
Chris@538
|
210 std::deque<QString> pending;
|
Chris@538
|
211 pending.push_back(path);
|
Chris@538
|
212
|
Chris@538
|
213 while (!pending.empty()) {
|
Chris@538
|
214
|
Chris@538
|
215 QString path = pending.front();
|
Chris@538
|
216 pending.pop_front();
|
Chris@538
|
217 if (!alreadyWatched.contains(path)) {
|
Chris@538
|
218 m_watcher.addPath(path);
|
Chris@540
|
219 m_dirContents[path] = scanDirectory(path);
|
Chris@538
|
220 }
|
Chris@538
|
221
|
Chris@538
|
222 QDir d(path);
|
Chris@538
|
223 if (d.exists()) {
|
Chris@538
|
224 d.setFilter(QDir::Dirs | QDir::NoDotAndDotDot |
|
Chris@538
|
225 QDir::Readable | QDir::NoSymLinks);
|
Chris@538
|
226 foreach (QString entry, d.entryList()) {
|
Chris@538
|
227 if (entry.startsWith('.')) continue;
|
Chris@538
|
228 QString entryPath = d.absoluteFilePath(entry);
|
Chris@538
|
229 pending.push_back(entryPath);
|
Chris@538
|
230 }
|
Chris@538
|
231 }
|
Chris@538
|
232 }
|
Chris@584
|
233 #endif
|
Chris@584
|
234 }
|
Chris@584
|
235
|
Chris@584
|
236 void
|
Chris@584
|
237 FsWatcher::setTrackedFilePaths(QStringList paths)
|
Chris@584
|
238 {
|
Chris@584
|
239 #ifdef Q_OS_MAC
|
Chris@586
|
240
|
Chris@586
|
241 // FSEvents will notify when any file in the directory changes,
|
Chris@586
|
242 // but we need to be able to check whether the file change was
|
Chris@586
|
243 // meaningful to us if it didn't result in any files being added
|
Chris@586
|
244 // or removed -- and we have to do that by examining timestamps on
|
Chris@586
|
245 // the files we care about
|
Chris@586
|
246 foreach (QString p, paths) {
|
Chris@586
|
247 m_trackedFileUpdates[p] = QDateTime::currentDateTime();
|
Chris@586
|
248 }
|
Chris@586
|
249
|
Chris@584
|
250 #else
|
Chris@586
|
251
|
Chris@584
|
252 QMutexLocker locker(&m_mutex);
|
Chris@584
|
253
|
Chris@584
|
254 QSet<QString> alreadyWatched =
|
Chris@584
|
255 QSet<QString>::fromList(m_watcher.files());
|
Chris@584
|
256
|
Chris@584
|
257 foreach (QString path, paths) {
|
Chris@584
|
258 path = m_workDirPath + QDir::separator() + path;
|
Chris@584
|
259 if (!alreadyWatched.contains(path)) {
|
Chris@584
|
260 m_watcher.addPath(path);
|
Chris@584
|
261 } else {
|
Chris@584
|
262 alreadyWatched.remove(path);
|
Chris@584
|
263 }
|
Chris@584
|
264 }
|
Chris@584
|
265
|
Chris@584
|
266 // Remove the remaining paths, those that were being watched
|
Chris@584
|
267 // before but that are not in the list we were given
|
Chris@584
|
268 foreach (QString path, alreadyWatched) {
|
Chris@584
|
269 m_watcher.removePath(path);
|
Chris@584
|
270 }
|
Chris@584
|
271
|
Chris@584
|
272 debugPrint();
|
Chris@586
|
273
|
Chris@584
|
274 #endif
|
Chris@538
|
275 }
|
Chris@538
|
276
|
Chris@538
|
277 void
|
Chris@538
|
278 FsWatcher::setIgnoredFilePrefixes(QStringList prefixes)
|
Chris@538
|
279 {
|
Chris@538
|
280 QMutexLocker locker(&m_mutex);
|
Chris@538
|
281 m_ignoredPrefixes = prefixes;
|
Chris@538
|
282 }
|
Chris@538
|
283
|
Chris@538
|
284 void
|
Chris@538
|
285 FsWatcher::setIgnoredFileSuffixes(QStringList suffixes)
|
Chris@538
|
286 {
|
Chris@538
|
287 QMutexLocker locker(&m_mutex);
|
Chris@538
|
288 m_ignoredSuffixes = suffixes;
|
Chris@538
|
289 }
|
Chris@538
|
290
|
Chris@538
|
291 int
|
Chris@538
|
292 FsWatcher::getNewToken()
|
Chris@538
|
293 {
|
Chris@538
|
294 QMutexLocker locker(&m_mutex);
|
Chris@538
|
295 int token = ++m_lastToken;
|
Chris@538
|
296 m_tokenMap[token] = m_lastCounter;
|
Chris@538
|
297 return token;
|
Chris@538
|
298 }
|
Chris@538
|
299
|
Chris@538
|
300 QSet<QString>
|
Chris@538
|
301 FsWatcher::getChangedPaths(int token)
|
Chris@538
|
302 {
|
Chris@538
|
303 QMutexLocker locker(&m_mutex);
|
Chris@538
|
304 size_t lastUpdatedAt = m_tokenMap[token];
|
Chris@538
|
305 QSet<QString> changed;
|
Chris@538
|
306 for (QHash<QString, size_t>::const_iterator i = m_changes.begin();
|
Chris@593
|
307 i != m_changes.end(); ++i) {
|
Chris@593
|
308 if (i.value() > lastUpdatedAt) {
|
Chris@593
|
309 changed.insert(i.key());
|
Chris@593
|
310 }
|
Chris@538
|
311 }
|
Chris@538
|
312 m_tokenMap[token] = m_lastCounter;
|
Chris@538
|
313 return changed;
|
Chris@538
|
314 }
|
Chris@538
|
315
|
Chris@538
|
316 void
|
Chris@538
|
317 FsWatcher::fsDirectoryChanged(QString path)
|
Chris@538
|
318 {
|
Chris@586
|
319 bool haveChanges = false;
|
Chris@586
|
320
|
Chris@538
|
321 {
|
Chris@538
|
322 QMutexLocker locker(&m_mutex);
|
Chris@540
|
323
|
Chris@538
|
324 if (shouldIgnore(path)) return;
|
Chris@540
|
325
|
Chris@540
|
326 QSet<QString> files = scanDirectory(path);
|
Chris@586
|
327
|
Chris@540
|
328 if (files == m_dirContents[path]) {
|
Chris@586
|
329
|
Chris@540
|
330 #ifdef DEBUG_FSWATCHER
|
Chris@593
|
331 std::cerr << "FsWatcher: Directory " << path << " has changed, but not in a way that we are monitoring -- doing manual check" << std::endl;
|
Chris@540
|
332 #endif
|
Chris@586
|
333
|
Chris@586
|
334 #ifdef Q_OS_MAC
|
Chris@586
|
335 haveChanges = manuallyCheckTrackedFiles();
|
Chris@586
|
336 #endif
|
Chris@586
|
337
|
Chris@541
|
338 } else {
|
Chris@586
|
339
|
Chris@541
|
340 #ifdef DEBUG_FSWATCHER
|
Chris@541
|
341 std::cerr << "FsWatcher: Directory " << path << " has changed" << std::endl;
|
Chris@541
|
342 #endif
|
Chris@541
|
343 m_dirContents[path] = files;
|
Chris@586
|
344 size_t counter = ++m_lastCounter;
|
Chris@586
|
345 m_changes[path] = counter;
|
Chris@586
|
346 haveChanges = true;
|
Chris@540
|
347 }
|
Chris@538
|
348 }
|
Chris@540
|
349
|
Chris@586
|
350 if (haveChanges) {
|
Chris@586
|
351 emit changed();
|
Chris@586
|
352 }
|
Chris@538
|
353 }
|
Chris@538
|
354
|
Chris@538
|
355 void
|
Chris@538
|
356 FsWatcher::fsFileChanged(QString path)
|
Chris@538
|
357 {
|
Chris@540
|
358 {
|
Chris@540
|
359 QMutexLocker locker(&m_mutex);
|
Chris@540
|
360
|
Chris@540
|
361 // We don't check whether the file matches an ignore pattern,
|
Chris@540
|
362 // because we are only notified for file changes if we are
|
Chris@540
|
363 // watching the file explicitly, i.e. the file is in the
|
Chris@586
|
364 // tracked file paths list. So we never want to ignore these
|
Chris@540
|
365
|
Chris@563
|
366 #ifdef DEBUG_FSWATCHER
|
Chris@541
|
367 std::cerr << "FsWatcher: Tracked file " << path << " has changed" << std::endl;
|
Chris@563
|
368 #endif
|
Chris@541
|
369
|
Chris@540
|
370 size_t counter = ++m_lastCounter;
|
Chris@540
|
371 m_changes[path] = counter;
|
Chris@540
|
372 }
|
Chris@540
|
373
|
Chris@540
|
374 emit changed();
|
Chris@538
|
375 }
|
Chris@538
|
376
|
Chris@586
|
377 #ifdef Q_OS_MAC
|
Chris@586
|
378 bool
|
Chris@586
|
379 FsWatcher::manuallyCheckTrackedFiles()
|
Chris@586
|
380 {
|
Chris@647
|
381 #ifdef DEBUG_FSWATCHER
|
Chris@593
|
382 std::cerr << "FsWatcher::manuallyCheckTrackedFiles" << std::endl;
|
Chris@647
|
383 #endif
|
Chris@586
|
384 bool foundChanges = false;
|
Chris@586
|
385
|
Chris@586
|
386 for (PathTimeMap::iterator i = m_trackedFileUpdates.begin();
|
Chris@586
|
387 i != m_trackedFileUpdates.end(); ++i) {
|
Chris@586
|
388
|
Chris@586
|
389 QString path = i.key();
|
Chris@586
|
390 QDateTime prevUpdate = i.value();
|
Chris@586
|
391
|
Chris@593
|
392 QFileInfo fi(m_workDirPath + QDir::separator() + path);
|
Chris@586
|
393 QDateTime currUpdate = fi.lastModified();
|
Chris@586
|
394
|
Chris@593
|
395 // std::cerr << "FsWatcher: Tracked file " << path << " previously changed at "
|
Chris@593
|
396 // << prevUpdate.toString().toStdString()
|
Chris@593
|
397 // << ", currently at " << currUpdate.toString().toStdString() << std::endl;
|
Chris@593
|
398
|
Chris@586
|
399 if (currUpdate > prevUpdate) {
|
Chris@586
|
400
|
Chris@586
|
401 #ifdef DEBUG_FSWATCHER
|
Chris@586
|
402 std::cerr << "FsWatcher: Tracked file " << path << " has been changed since last check" << std::endl;
|
Chris@586
|
403 #endif
|
Chris@586
|
404 i.value() = currUpdate;
|
Chris@586
|
405
|
Chris@586
|
406 size_t counter = ++m_lastCounter;
|
Chris@586
|
407 m_changes[path] = counter;
|
Chris@586
|
408 foundChanges = true;
|
Chris@586
|
409 }
|
Chris@586
|
410 }
|
Chris@586
|
411
|
Chris@586
|
412 return foundChanges;
|
Chris@586
|
413 }
|
Chris@586
|
414 #endif
|
Chris@586
|
415
|
Chris@538
|
416 bool
|
Chris@538
|
417 FsWatcher::shouldIgnore(QString path)
|
Chris@538
|
418 {
|
Chris@540
|
419 QFileInfo fi(path);
|
Chris@540
|
420 QString fn(fi.fileName());
|
Chris@540
|
421 foreach (QString pfx, m_ignoredPrefixes) {
|
Chris@541
|
422 if (fn.startsWith(pfx)) {
|
Chris@563
|
423 #ifdef DEBUG_FSWATCHER
|
Chris@541
|
424 std::cerr << "(ignoring: " << path << ")" << std::endl;
|
Chris@563
|
425 #endif
|
Chris@541
|
426 return true;
|
Chris@541
|
427 }
|
Chris@540
|
428 }
|
Chris@540
|
429 foreach (QString sfx, m_ignoredSuffixes) {
|
Chris@541
|
430 if (fn.endsWith(sfx)) {
|
Chris@563
|
431 #ifdef DEBUG_FSWATCHER
|
Chris@541
|
432 std::cerr << "(ignoring: " << path << ")" << std::endl;
|
Chris@563
|
433 #endif
|
Chris@541
|
434 return true;
|
Chris@541
|
435 }
|
Chris@540
|
436 }
|
Chris@540
|
437 return false;
|
Chris@538
|
438 }
|
Chris@538
|
439
|
Chris@540
|
440 QSet<QString>
|
Chris@540
|
441 FsWatcher::scanDirectory(QString path)
|
Chris@540
|
442 {
|
Chris@540
|
443 QSet<QString> files;
|
Chris@540
|
444 QDir d(path);
|
Chris@540
|
445 if (d.exists()) {
|
Chris@540
|
446 d.setFilter(QDir::Files | QDir::NoDotAndDotDot |
|
Chris@540
|
447 QDir::Readable | QDir::NoSymLinks);
|
Chris@540
|
448 foreach (QString entry, d.entryList()) {
|
Chris@540
|
449 if (entry.startsWith('.')) continue;
|
Chris@540
|
450 if (shouldIgnore(entry)) continue;
|
Chris@540
|
451 files.insert(entry);
|
Chris@540
|
452 }
|
Chris@540
|
453 }
|
Chris@540
|
454 return files;
|
Chris@540
|
455 }
|
Chris@540
|
456
|
Chris@540
|
457 void
|
Chris@540
|
458 FsWatcher::debugPrint()
|
Chris@540
|
459 {
|
Chris@540
|
460 #ifdef DEBUG_FSWATCHER
|
Chris@585
|
461 #ifndef Q_OS_MAC
|
Chris@540
|
462 std::cerr << "FsWatcher: Now watching " << m_watcher.directories().size()
|
Chris@540
|
463 << " directories and " << m_watcher.files().size()
|
Chris@540
|
464 << " files" << std::endl;
|
Chris@540
|
465 #endif
|
Chris@585
|
466 #endif
|
Chris@540
|
467 }
|