1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import os
20 import os.path
21 import gobject
22 import gio
23 import util
24 import debuglog
25
26 N_WATCHES_LIMIT = 200
27
28 CHANGED = gio.FILE_MONITOR_EVENT_CHANGED
29 DELETED = gio.FILE_MONITOR_EVENT_DELETED
30 CREATED = gio.FILE_MONITOR_EVENT_CREATED
31
34
36 if event == CHANGED:
37 return "changed"
38 elif event == DELETED:
39 return "deleted"
40 elif event == CREATED:
41 return "created"
42 else:
43 return "invalid"
44
46 - def __init__ (self, directory, callback, data = None):
47 self.directory = directory
48 self.callback = callback
49 self.data = data
50 self.watches = {}
51 self.too_many_watches = False
52 self.dirs_to_ignore = []
53 self.files_to_ignore = []
54
56 assert len (self.watches) == 0
57 self.dirs_to_ignore = dirs
58 dprint ("Ignoring directories %s", self.dirs_to_ignore)
59
61 assert len (self.watches) == 0
62 self.files_to_ignore = files
63 dprint ("Ignoring files %s", self.files_to_ignore)
64
65
66
67
69 dprint ("Invoking callback for %s - %s", path, event_to_string (event))
70 if self.data:
71 self.callback (path, event, self.data)
72 else:
73 self.callback (path, event)
74
75
76
77
102
105
108
110 dir = os.path.normpath (dir)
111
112 if len (self.watches) >= N_WATCHES_LIMIT:
113 if not self.too_many_watches:
114 print "Too many directories to watch on %s" % (self.directory)
115 self.too_many_watches = True
116 return
117
118 try:
119 gfile = gio.File (dir)
120 self.watches [dir] = gfile.monitor_directory ()
121 self.watches [dir].connect ("changed", self.__handle_file_monitor_event)
122 dprint ("Added directory watch for '%s'", dir)
123 except:
124 print ("Failed to add monitor for %s") % (dir)
125 util.print_exception ()
126
150
152 dprint ("Starting to recursively monitor '%s'", self.directory)
153 self.__monitor_dir (self.directory)
154 self.__monitor_dir_recurse (self.directory)
155 dprint ("Ending recursive scan of '%s'; all monitors are in place now", self.directory)
156
158 dprint ("Stopping recursive monitoring of '%s'", self.directory)
159
160 for path in self.watches:
161 self.watches [path].cancel ()
162
164 import tempfile
165 import shutil
166
167 temp_path = tempfile.mkdtemp (prefix = "test-monitor-")
168
169 def handle_change (path, event, data):
170 (expected, main_loop) = data
171 if len (expected) > 0:
172 i = 0
173 for (expected_path, expected_event) in expected:
174 if expected_path == path and expected_event == event:
175 break
176 i += 1
177 if i < len (expected):
178 del expected[i]
179 if len (expected) == 0:
180 main_loop.quit ()
181
182 def expect (expected, path, event):
183 expected.append ((path, event))
184
185 main_loop = gobject.MainLoop ()
186
187 expected = []
188 def should_not_be_reached (expected):
189 for (path, event) in expected:
190 print ("Expected event: %s %s") % (path, event_to_string (event))
191 assert False
192 return True
193 timeout = gobject.timeout_add_seconds (5, should_not_be_reached, expected)
194
195 monitor = DirectoryMonitor (temp_path, handle_change, (expected, main_loop))
196 monitor.set_directories_to_ignore (["bar"])
197 monitor.set_files_to_ignore (["foobar/foo/foo.txt"])
198 monitor.start ()
199
200 expect (expected, os.path.join (temp_path, "foo.txt"), CREATED)
201 f = file (os.path.join (temp_path, "foo.txt"), "w")
202 f.close ()
203
204
205
206 os.mkdir (os.path.join (temp_path, "bar"))
207
208 expect (expected, os.path.join (temp_path, "foobar"), CREATED)
209 expect (expected, os.path.join (temp_path, "foobar/foo"), CREATED)
210 expect (expected, os.path.join (temp_path, "foobar/foo/bar"), CREATED)
211 expect (expected, os.path.join (temp_path, "foobar/foo/bar/foo"), CREATED)
212 expect (expected, os.path.join (temp_path, "foobar/foo/bar/foo/bar"), CREATED)
213 os.makedirs (os.path.join (temp_path, "foobar/foo/bar/foo/bar"))
214
215
216
217 f = file (os.path.join (temp_path, "foobar/foo/foo.txt"), "w")
218 f.close ()
219
220 main_loop.run ()
221
222 expect (expected, os.path.join (temp_path, "foobar/foo/bar/foo/bar"), DELETED)
223 expect (expected, os.path.join (temp_path, "foobar/foo/bar/foo"), DELETED)
224 expect (expected, os.path.join (temp_path, "foobar/foo/bar"), DELETED)
225
226
227 expect (expected, os.path.join (temp_path, "foobar/foo"), DELETED)
228 expect (expected, os.path.join (temp_path, "foobar"), DELETED)
229
230
231 expect (expected, os.path.join (temp_path, "foo.txt"), DELETED)
232
233
234
235 expect (expected, temp_path, DELETED)
236
237 shutil.rmtree (temp_path, True)
238
239 main_loop.run ()
240
241 gobject.source_remove (timeout)
242
243 monitor.stop ()
244