File: fs_win32.py

package info (click to toggle)
taskcoach 1.4.1-4
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 32,496 kB
  • ctags: 17,810
  • sloc: python: 72,170; makefile: 254; ansic: 120; xml: 29; sh: 16
file content (127 lines) | stat: -rw-r--r-- 4,407 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
'''
Task Coach - Your friendly task manager
Copyright (C) 2011 Task Coach developers <developers@taskcoach.org>

Task Coach is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Task Coach is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''

from win32file import *
from win32con import *
from win32event import *
import os, threading
from taskcoachlib.filesystem import base


class DirectoryWatcher(object):
    ADDED       = 1
    REMOVED     = 2
    MODIFIED    = 3
    RENAMED_OLD = 4
    RENAMED_NEW = 5

    def __init__(self, path):
        super(DirectoryWatcher, self).__init__()

        self.dirHandle = CreateFile(path,
                                    GENERIC_READ,
                                    FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
                                    None,
                                    OPEN_EXISTING,
                                    FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED,
                                    0)
        self.buffer = AllocateReadBuffer(8192)
        self.overlapped = OVERLAPPED()
        self.overlapped.hEvent = CreateEvent(None, False, False, None)

    def wait(self, recurse=False, timeout=INFINITE):
        ReadDirectoryChangesW(self.dirHandle, self.buffer, recurse,
                              FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | \
                              FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | \
                              FILE_NOTIFY_CHANGE_LAST_WRITE,
                              self.overlapped)

        rc = WaitForSingleObject(self.overlapped.hEvent, timeout)
        if rc == WAIT_OBJECT_0:
            try:
                size = GetOverlappedResult(self.dirHandle, self.overlapped, True)
            except Exception, e:
                if e.args[0] == 995:
                    return None
                raise
            if size == 0:
                return None
            else:
                return FILE_NOTIFY_INFORMATION(self.buffer, size)

    def stop(self):
        CloseHandle(self.dirHandle)


class FilesystemNotifier(base.NotifierBase):
    def __init__(self):
        super(FilesystemNotifier, self).__init__()

        self.watcher = None
        self.thread = None
        self.lock = threading.Lock()

    def setFilename(self, filename):
        self.lock.acquire()
        try:
            if self.watcher is not None:
                self.watcher.stop()
                self.thread.join()
                self.watcher = None
                self.thread = None
            super(FilesystemNotifier, self).setFilename(filename)
            if self._filename:
                self.watcher = DirectoryWatcher(self._path)
                self.thread = threading.Thread(target=self._run)
                self.thread.setDaemon(True)
                self.thread.start()
        finally:
            self.lock.release()

    def stop(self):
        self.lock.acquire()
        try:
            if self.watcher is not None:
                self.watcher.stop()
                self.thread.join()
                self.watcher = None
                self.thread = None
        finally:
            self.lock.release()

    def onFileChanged(self):
        raise NotImplementedError

    def _run(self):
        while True:
            self.lock.acquire()
            try:
                watcher, myname = self.watcher, self._filename
            finally:
                self.lock.release()

            if watcher is not None:
                changes = watcher.wait()
                if changes is None:
                    return
                for change, name in changes:
                    if name == os.path.split(myname)[-1]:
                        if self._check(myname) and myname:
                            self.stamp = os.stat(myname).st_mtime
                            self.onFileChanged()
                            break