130
130
class Watch(object):
131
131
"""Implement the same functions as pyinotify.Watch."""
133
def __init__(self, watch_descriptor, path, mask, auto_add, processor,
133
def __init__(self, watch_descriptor, path, mask, processor, buf_size=8192):
135
134
super(Watch, self).__init__()
136
135
self.log = logging.getLogger('ubuntuone.SyncDaemon.platform.windows.' +
137
136
'filesystem_notifications.Watch')
143
142
self._overlapped.hEvent = CreateEvent(None, 0, 0, None)
144
143
self._watching = False
145
144
self._descriptor = watch_descriptor
146
self._auto_add = auto_add
145
# ignored paths are those that we actually do want to ignore while
146
# not watched paths are those whose events are not propagated to
147
# mimic the linux behaviour
147
148
self._ignore_paths = []
149
self._not_watched_paths = []
148
150
self._cookie = None
149
151
self._source_pathname = None
150
152
self._process_thread = None
212
214
if any([file_name.startswith(path)
213
215
for path in self._ignore_paths]):
217
if any([file_name.startswith(path)
218
for path in self._not_watched_paths]):
215
220
# map the windows events to the pyinotify ones, tis is dirty but
216
221
# makes the multiplatform better, linux was first :P
217
222
syncdaemon_path = get_syncdaemon_valid_path(
325
330
reactor.callFromThread(self._process_events, events)
327
332
@is_valid_windows_path(path_indexes=[1])
333
def _add_path_to_collection(self, path, collection):
334
"""Adds the given path to a collection."""
335
if not path.endswith(os.path.sep):
337
if path.startswith(self._path):
338
path = path[len(self._path):]
339
collection.append(path)
341
def _ignore_child(self, path):
342
"""Ignore the given child."""
343
self._add_path_to_collection(path, self._not_watched_paths)
328
345
def ignore_path(self, path):
329
346
"""Add the path of the events to ignore."""
347
self._add_path_to_collection(path, self._ignore_paths)
349
@is_valid_windows_path(path_indexes=[1])
350
def _remove_ignored_child(self, path):
330
351
if not path.endswith(os.path.sep):
331
352
path += os.path.sep
332
353
if path.startswith(self._path):
333
354
path = path[len(self._path):]
334
self._ignore_paths.append(path)
355
if path in self._not_watched_paths:
356
self._not_watched_paths.remove(path)
336
358
@is_valid_windows_path(path_indexes=[1])
337
359
def remove_ignored_path(self, path):
355
377
for current_child in native_listdir(path):
356
378
full_child_path = os.path.join(self._path, current_child)
357
379
if os.path.isdir(full_child_path):
358
self.ignore_path(full_child_path)
380
self._ignore_child(full_child_path)
359
381
# lets remove the path from the ignored paths since the children are
360
382
# the ones ignored.
361
self.remove_ignored_path(path)
383
self._remove_ignored_child(path)
363
385
def start_watching(self):
364
386
"""Tell the watch to start processing events."""
372
394
# when we start watching we will add the suddirs to the list of
373
395
# ignored paths, later this paths will be removed if a watch is
375
self.ignore_path(full_child_path)
397
self._ignore_child(full_child_path)
376
398
# start to diff threads, one to watch the path, the other to
377
399
# process the events.
378
400
self.log.debug('Start watching path.')
388
410
self._subdirs = set()
389
411
return self.stopped
391
def update(self, mask, auto_add=False):
413
def update(self, mask):
392
414
"""Update the info used by the watcher."""
393
self.log.debug('update(%s, %s)', mask, auto_add)
415
self.log.debug('update(%s, %s)', mask)
394
416
self._mask = mask
395
self._auto_add = auto_add
456
473
except KeyError, e:
457
474
logging.error(str(e))
459
def _add_single_watch(self, path, mask, auto_add=False,
476
def _add_single_watch(self, path, mask, quiet=True):
461
477
if path in self._ignored_paths:
462
478
# simply removed it from the filter
463
479
self._ignored_paths.remove(path)
465
481
# we need to add a new watch
466
self.log.debug('add_single_watch(%s, %s, %s, %s)', path, mask,
482
self.log.debug('add_single_watch(%s, %s, %s)', path, mask,
469
485
# adjust the number of threads based on the UDFs watched
470
486
reactor.suggestThreadPoolSize(THREADPOOL_MAX + self._wd_count + 1)
471
487
self._wdm[self._wd_count] = Watch(self._wd_count, path,
472
mask, auto_add, self._processor)
488
mask, self._processor)
473
489
d = self._wdm[self._wd_count].start_watching()
474
490
self._wd_count += 1
477
493
@is_valid_windows_path(path_indexes=[1])
478
def add_watch(self, path, mask, auto_add=False,
494
def add_watch(self, path, mask, quiet=True):
480
495
"""Add a new path to be watch.
482
497
The method will ensure that the path is not already present.
487
502
wd = self.get_wd(path)
489
504
self.log.debug('Adding single watch on %r', path)
490
return self._add_single_watch(path, mask, auto_add, quiet)
505
return self._add_single_watch(path, mask, quiet)
492
507
self.log.debug('Watch already exists on %r', path)
493
self._wdm[wd].add_child_watch(path)
508
if path != self._wdm[wd].path:
509
self._wdm[wd].add_child_watch(path)
494
510
return self._wdm[wd].started
496
def update_watch(self, wd, mask=None, rec=False,
497
auto_add=False, quiet=True):
512
def update_watch(self, wd, mask=None, rec=False, quiet=True):
498
513
raise NotImplementedError("Not implemented on windows.")
500
515
@is_valid_windows_path(path_indexes=[1])
504
519
path = path + os.path.sep
505
520
for current_wd in self._wdm:
506
521
watch_path = self._wdm[current_wd].path
507
if ((watch_path == path or (
508
watch_path in path and self._wdm[current_wd].auto_add))
522
if (watch_path in path
509
523
and path not in self._ignored_paths):
510
524
return current_wd
784
798
# the logic to check if the watch is already set
785
799
# is all in WatchManager.add_watch
786
800
return self._watch_manager.add_watch(dirpath,
787
FILESYSTEM_MONITOR_MASK, auto_add=True)
801
FILESYSTEM_MONITOR_MASK)
789
803
def add_watches_to_udf_ancestors(self, volume):
790
804
"""Add a inotify watch to volume's ancestors if it's an UDF."""