~mandel/ubuntuone-client/add-virtual-watches

« back to all changes in this revision

Viewing changes to ubuntuone/platform/windows/filesystem_notifications.py

  • Committer: manuel.delapena at canonical
  • Date: 2012-01-13 12:14:49 UTC
  • Revision ID: manuel.delapena@canonical.com-20120113121449-kydmx06sx4s2rr72
Changed the code in tests to be a little simplet.

Show diffs side-by-side

added added

removed removed

Lines of Context:
130
130
class Watch(object):
131
131
    """Implement the same functions as pyinotify.Watch."""
132
132
 
133
 
    def __init__(self, watch_descriptor, path, mask, auto_add, processor,
134
 
        buf_size=8192):
 
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]):
214
216
                continue
 
217
            if any([file_name.startswith(path)
 
218
                        for path in self._not_watched_paths]):
 
219
                continue
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(
300
305
            ReadDirectoryChangesW(
301
306
                handle,
302
307
                buf,
303
 
                self._auto_add,
 
308
                True,
304
309
                self._mask,
305
310
                self._overlapped,
306
311
            )
325
330
            reactor.callFromThread(self._process_events, events)
326
331
 
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):
 
336
            path += os.path.sep
 
337
        if path.startswith(self._path):
 
338
            path = path[len(self._path):]
 
339
            collection.append(path)
 
340
 
 
341
    def _ignore_child(self, path):
 
342
        """Ignore the given child."""
 
343
        self._add_path_to_collection(path, self._not_watched_paths)
 
344
 
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)
 
348
    
 
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)
335
357
 
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)
362
384
 
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
374
396
                # added to them.
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
390
412
 
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
396
417
 
397
418
    @property
398
419
    def path(self):
400
421
        return self._path
401
422
 
402
423
    @property
403
 
    def auto_add(self):
404
 
        return self._auto_add
405
 
 
406
 
    @property
407
424
    def started(self):
408
425
        """A deferred that will be called when the watch is running."""
409
426
        return self._watch_started_deferred
456
473
        except KeyError, e:
457
474
            logging.error(str(e))
458
475
 
459
 
    def _add_single_watch(self, path, mask, auto_add=False,
460
 
        quiet=True):
 
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)
464
480
            return
465
481
        # we need to add a new watch
466
 
        self.log.debug('add_single_watch(%s, %s, %s, %s)', path, mask,
467
 
            auto_add, quiet)
 
482
        self.log.debug('add_single_watch(%s, %s, %s)', path, mask,
 
483
            quiet)
468
484
 
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
475
491
        return d
476
492
 
477
493
    @is_valid_windows_path(path_indexes=[1])
478
 
    def add_watch(self, path, mask, auto_add=False,
479
 
        quiet=True):
 
494
    def add_watch(self, path, mask, quiet=True):
480
495
        """Add a new path to be watch.
481
496
 
482
497
        The method will ensure that the path is not already present.
487
502
        wd = self.get_wd(path)
488
503
        if wd is None:
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)
491
506
        else:
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
495
511
 
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.")
499
514
 
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
511
525
 
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)
788
802
 
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."""