~nataliabidart/ubuntuone-client/login-email-password-for-everyone

« back to all changes in this revision

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

  • Committer: Tarmac
  • Author(s): Alejandro J. Cura
  • Date: 2011-08-19 21:08:38 UTC
  • mfrom: (1102.3.9 watch-finished-deferred)
  • Revision ID: tarmac-20110819210838-p9xl304cyur4szq0
A deferred that is fired when watches are completely removed. (LP: #824819)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
1
2
# Authors: Manuel de la Pena <manuel@canonical.com>
2
3
#          Natalia B. Bidart <natalia.bidart@canonical.com>
 
4
#          Alejandro J. Cura <alecu@canonical.com>
3
5
#
4
6
# Copyright 2011 Canonical Ltd.
5
7
#
23
25
from uuid import uuid4
24
26
 
25
27
from twisted.internet import defer, reactor
 
28
from twisted.python.failure import Failure
26
29
from pywintypes import OVERLAPPED
27
30
from win32api import CloseHandle
28
31
from win32con import (
137
140
        self._cookie = None
138
141
        self._source_pathname = None
139
142
        self._process_thread = None
 
143
        self._watch_handle = None
140
144
        # remember the subdirs we have so that when we have a delete we can
141
145
        # check if it was a remove
142
146
        self._subdirs = []
149
153
        # this deferred is fired when the watch has started monitoring
150
154
        # a directory from a thread
151
155
        self._watch_started_deferred = defer.Deferred()
 
156
        # and this one is fired when the watch has stopped
 
157
        self._watch_stopped_deferred = defer.Deferred()
152
158
 
153
159
    @is_valid_windows_path(path_indexes=[1])
154
160
    def _path_is_dir(self, path):
170
176
        return is_dir
171
177
 
172
178
    def _process_events(self, events):
173
 
        """Process the events form the queue."""
 
179
        """Process the events from the queue."""
174
180
        # do not do it if we stop watching and the events are empty
175
181
        if not self._watching:
176
182
            return
227
233
        """Wrap _watch, and errback on any unhandled error."""
228
234
        try:
229
235
            self._watch()
230
 
        except Exception as error:
 
236
        except Exception:
231
237
            reactor.callFromThread(self._call_deferred,
232
 
                self._watch_started_deferred.errback, error)
 
238
                self._watch_started_deferred.errback, Failure())
233
239
 
234
240
    def _watch(self):
235
241
        """Watch a path that is a directory."""
238
244
                       os.path.exists(self._path), os.path.isdir(self._path))
239
245
        # we are going to be using the ReadDirectoryChangesW whihc requires
240
246
        # a directory handle and the mask to be used.
241
 
        handle = CreateFileW(
 
247
        self._watch_handle = CreateFileW(
242
248
            self._path,
243
249
            FILE_LIST_DIRECTORY,
244
250
            FILE_SHARE_READ | FILE_SHARE_WRITE,
248
254
            None)
249
255
 
250
256
        try:
251
 
            self._watch_loop(handle)
 
257
            self._watch_loop(self._watch_handle)
252
258
        finally:
253
 
            CloseHandle(handle)
 
259
            CloseHandle(self._watch_handle)
 
260
            self._watch_handle = None
 
261
            reactor.callFromThread(self.stopped.callback, True)
254
262
 
255
263
    def _watch_loop(self, handle):
256
264
        """The loop where we watch the directory."""
325
333
        SetEvent(self._wait_stop)
326
334
        self._watching = False
327
335
        self._subdirs = []
 
336
        return self.stopped
328
337
 
329
338
    def update(self, mask, auto_add=False):
330
339
        """Update the info used by the watcher."""
346
355
        """A deferred that will be called when the watch is running."""
347
356
        return self._watch_started_deferred
348
357
 
 
358
    @property
 
359
    def stopped(self):
 
360
        """A deferred fired when the watch thread has finished."""
 
361
        return self._watch_stopped_deferred
 
362
 
349
363
 
350
364
class WatchManager(object):
351
365
    """Implement the same functions as pyinotify.WatchManager.
368
382
    def stop(self):
369
383
        """Close the manager and stop all watches."""
370
384
        self.log.debug('Stopping watches.')
 
385
        wait_list = []
371
386
        for current_wd in self._wdm:
372
 
            self._wdm[current_wd].stop_watching()
373
 
            self.log.debug('Watch for %s stopped.', self._wdm[current_wd].path)
 
387
            wait_list.append(self._wdm[current_wd].stop_watching())
 
388
            self.log.debug('Stopping Watch on %r.', self._wdm[current_wd].path)
 
389
        return defer.DeferredList(wait_list)
374
390
 
375
391
    def get_watch(self, wd):
376
392
        """Return the watch with the given descriptor."""
377
393
        return self._wdm[wd]
378
394
 
 
395
    @defer.inlineCallbacks
379
396
    def del_watch(self, wd):
380
397
        """Delete the watch with the given descriptor."""
381
398
        try:
382
399
            watch = self._wdm[wd]
383
 
            watch.stop_watching()
 
400
            yield watch.stop_watching()
384
401
            del self._wdm[wd]
385
402
            self.log.debug('Watch %s removed.', wd)
386
403
        except KeyError, e:
445
462
        if watch:
446
463
            return watch.path
447
464
 
 
465
    @defer.inlineCallbacks
448
466
    def rm_watch(self, wd, rec=False, quiet=True):
449
467
        """Remove the the watch with the given wd."""
450
468
        try:
451
469
            watch = self._wdm[wd]
452
 
            watch.stop_watching()
 
470
            yield watch.stop_watching()
453
471
            del self._wdm[wd]
454
472
        except KeyError, err:
455
473
            self.log.error(str(err))
700
718
 
701
719
    def shutdown(self):
702
720
        """Prepares the EQ to be closed."""
703
 
        self._watch_manager.stop()
 
721
        return self._watch_manager.stop()
704
722
 
705
723
    @windowspath(path_indexes=[1])
706
724
    def rm_watch(self, dirpath):