Merge lp:~mandel/ubuntuone-client/fix-rm-path into lp:ubuntuone-client

Proposed by Manuel de la Peña
Status: Merged
Approved by: Natalia Bidart
Approved revision: 1107
Merged at revision: 1078
Proposed branch: lp:~mandel/ubuntuone-client/fix-rm-path
Merge into: lp:ubuntuone-client
Prerequisite: lp:~mandel/ubuntuone-client/remove_watcher_q
Diff against target: 381 lines (+188/-49)
2 files modified
tests/platform/windows/test_filesystem_notifications.py (+150/-18)
ubuntuone/platform/windows/filesystem_notifications.py (+38/-31)
To merge this branch: bzr merge lp:~mandel/ubuntuone-client/fix-rm-path
Reviewer Review Type Date Requested Status
Natalia Bidart (community) Approve
Guillermo Gonzalez Approve
Review via email: mp+69691@code.launchpad.net

Commit message

Improved the implementation of the rm_path method so that it is simpler.

Description of the change

Improved the implementation of the rm_path method so that it is simpler.

To post a comment you must log in.
1102. By Manuel de la Peña

Merged remove_watcher_q into fix-rm-path.

1103. By Manuel de la Peña

Merged remove_watcher_q into fix-rm-path.

1104. By Manuel de la Peña

Merged with previous branch.

1105. By Manuel de la Peña

Merged remove_watcher_q into fix-rm-path.

1106. By Manuel de la Peña

Merged remove_watcher_q into fix-rm-path.

Revision history for this message
Guillermo Gonzalez (verterok) wrote :

Looks ok, tests pass.

review: Approve
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Typo: test_undo_ignore_path_other_ignoed

Remove the "" from: self.log.debug('Adding exclude filter for "%r"', path)

review: Needs Fixing
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Also:
./tests/platform/windows/test_filesystem_notifications.py:
    632: local variable 'exclude_filter' is assigned to but never used

review: Needs Fixing
1107. By Manuel de la Peña

Fixed some small typos and removed an unused var.

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

All Clear!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'tests/platform/windows/test_filesystem_notifications.py'
2--- tests/platform/windows/test_filesystem_notifications.py 2011-07-28 20:13:00 +0000
3+++ tests/platform/windows/test_filesystem_notifications.py 2011-07-29 13:35:16 +0000
4@@ -448,13 +448,129 @@
5 self.assertEqual(0, len(events))
6 test_open_dir_muted.skip = "we must rethink this test."
7
8-
9-class FakeEvent():
10- """A fake event."""
11-
12- def __init__(self, path):
13- """Create an event with the given path."""
14- self.pathname = path
15+ def test_ignore_path(self):
16+ """Test that events from a path are ignored."""
17+ events = []
18+
19+ def fake_processor(event):
20+ """Memorize the processed events."""
21+ events.append(event)
22+
23+ path = u'\\\\?\\C:\\path' # a valid windows path
24+ child = u'child'
25+ watch = Watch(1, path, None, True, fake_processor)
26+ watch.ignore_path(os.path.join(path, child))
27+ paths_to_ignore = []
28+ for file_name in 'abcdef':
29+ paths_to_ignore.append((1, os.path.join(child, file_name)))
30+ # ensure that the watch is watching
31+ watch._watching = True
32+ watch._process_events(paths_to_ignore)
33+ self.assertEqual(0, len(events),
34+ 'All events should have been ignored.')
35+
36+ def test_not_ignore_path(self):
37+ """Test that we do get the events when they do not match."""
38+ events = []
39+
40+ def fake_processor(event):
41+ """Memorize the processed events."""
42+ events.append(event)
43+
44+ path = u'\\\\?\\C:\\path' # a valid windows path
45+ child = u'child'
46+ watch = Watch(1, path, None, True, fake_processor)
47+ watch.ignore_path(os.path.join(path, child))
48+ paths_not_to_ignore = []
49+ for file_name in 'abcdef':
50+ paths_not_to_ignore.append((1, os.path.join(
51+ child + file_name, file_name)))
52+ # ensure that the watch is watching
53+ watch._watching = True
54+ watch._process_events(paths_not_to_ignore)
55+ self.assertEqual(len(paths_not_to_ignore), len(events),
56+ 'No events should have been ignored.')
57+
58+ def test_mixed_ignore_path(self):
59+ """Test that we do get the correct events."""
60+ events = []
61+
62+ def fake_processor(event):
63+ """Memorize the processed events."""
64+ events.append(event.pathname)
65+
66+ child = u'child'
67+ path = u'\\\\?\\C:\\path\\' # a valid windows path
68+ watch = Watch(1, path, None, True, fake_processor)
69+ watch.ignore_path(os.path.join(path, child))
70+ paths_not_to_ignore = []
71+ paths_to_ignore = []
72+ expected_events = []
73+ for file_name in 'abcdef':
74+ valid = os.path.join(child + file_name, file_name)
75+ paths_to_ignore.append((1, os.path.join(child, file_name)))
76+ paths_not_to_ignore.append((1, valid))
77+ expected_events.append(os.path.join('C:\\path', valid))
78+ # ensure that the watch is watching
79+ watch._watching = True
80+ watch._process_events(paths_not_to_ignore)
81+ self.assertEqual(len(paths_not_to_ignore), len(events),
82+ 'Wrong number of events ignored.')
83+ self.assertTrue(all([event in expected_events for event in events]),
84+ 'Paths ignored that should have not been ignored.')
85+
86+ def test_undo_ignore_path_ignored(self):
87+ """Test that we do deal with events from and old ignored path."""
88+ events = []
89+
90+ def fake_processor(event):
91+ """Memorize the processed events."""
92+ events.append(event)
93+
94+ path = u'\\\\?\\C:\\path' # a valid windows path
95+ child = u'child'
96+ watch = Watch(1, path, None, True, fake_processor)
97+ watch.ignore_path(os.path.join(path, child))
98+ watch.remove_ignored_path(os.path.join(path, child))
99+ paths_not_to_ignore = []
100+ for file_name in 'abcdef':
101+ paths_not_to_ignore.append((1, os.path.join(child, file_name)))
102+ # ensure that the watch is watching
103+ watch._watching = True
104+ watch._process_events(paths_not_to_ignore)
105+ self.assertEqual(len(paths_not_to_ignore), len(events),
106+ 'All events should have been accepted.')
107+
108+ def test_undo_ignore_path_other_ignored(self):
109+ """Test that we can undo and the other path is ignored."""
110+ events = []
111+
112+ def fake_processor(event):
113+ """Memorize the processed events."""
114+ events.append(event.pathname)
115+
116+ path = u'\\\\?\\C:\\path' # a valid windows path
117+ child_a = u'childa'
118+ child_b = u'childb'
119+ watch = Watch(1, path, None, True, fake_processor)
120+ watch.ignore_path(os.path.join(path, child_a))
121+ watch.ignore_path(os.path.join(path, child_b))
122+ watch.remove_ignored_path(os.path.join(path, child_a))
123+ paths_to_ignore = []
124+ paths_not_to_ignore = []
125+ expected_events = []
126+ for file_name in 'abcdef':
127+ paths_to_ignore.append((1, os.path.join(child_b, file_name)))
128+ valid = os.path.join(child_a, file_name)
129+ paths_not_to_ignore.append((1, valid))
130+ expected_events.append(os.path.join('C:\\path', valid))
131+ # ensure that the watch is watching
132+ watch._watching = True
133+ watch._process_events(paths_not_to_ignore)
134+ self.assertEqual(len(paths_not_to_ignore), len(events),
135+ 'All events should have been accepted.')
136+ self.assertTrue(all([event in expected_events for event in events]),
137+ 'Paths ignored that should have not been ignored.')
138
139
140 class TestWatchManager(BaseTwistedTestCase):
141@@ -513,15 +629,12 @@
142
143 mask = 'bit_mask'
144 auto_add = True
145- exclude_filter = lambda x: False
146- self.manager.add_watch(self.path, mask, auto_add=auto_add,
147- exclude_filter=exclude_filter)
148+ self.manager.add_watch(self.path, mask, auto_add=auto_add)
149 self.assertEqual(1, len(self.manager._wdm))
150 self.assertTrue(self.was_called, 'The watch start was not called.')
151- self.assertEqual(self.path, self.manager._wdm[0]._path)
152+ self.assertEqual(self.path + os.path.sep, self.manager._wdm[0]._path)
153 self.assertEqual(mask, self.manager._wdm[0]._mask)
154 self.assertEqual(auto_add, self.manager._wdm[0]._auto_add)
155- self.assertEqual(exclude_filter, self.manager._wdm[0].exclude_filter)
156
157 def test_update_present_watch(self):
158 """Test the update of a present watch."""
159@@ -531,7 +644,7 @@
160
161 def test_get_watch_present_wd(self):
162 """Test that the correct path is returned."""
163- self.assertEqual(self.path, self.manager.get_path(1))
164+ self.assertEqual(self.path + os.path.sep, self.manager.get_path(1))
165
166 def test_get_watch_missing_wd(self):
167 """Test that the correct path is returned."""
168@@ -554,16 +667,35 @@
169
170 def test_rm_root_path(self):
171 """Test the removal of a root path."""
172+ events = []
173+
174+ def fake_processor(event):
175+ """Memorize the processed events."""
176+ events.append(event.pathname)
177+
178+ self.watch._processor = fake_processor
179 self.manager.rm_path(self.path)
180 self.assertEqual(self.watch, self.manager._wdm.get(1))
181- event = FakeEvent(self.path)
182- self.assertTrue(self.watch.exclude_filter(event))
183+ self.watch._watching = True
184+ self.watch._process_events([(1, os.path.join(self.path, 'test'))])
185+ self.assertEqual(0, len(events))
186
187 def test_rm_child_path(self):
188 """Test the removal of a child path."""
189+ events = []
190+
191+ def fake_processor(event):
192+ """Memorize the processed events."""
193+ events.append(event.pathname)
194+
195+ self.watch._processor = fake_processor
196 child = os.path.join(self.path, u'child')
197- event = FakeEvent(child)
198 self.manager.rm_path(child)
199 self.assertEqual(self.watch, self.manager._wdm[1])
200- # assert that the path is ignored
201- self.assertTrue(self.watch.exclude_filter(event))
202+ # assert that the correct event is ignored
203+ self.watch._watching = True
204+ self.watch._process_events([(1, os.path.join('child', 'test'))])
205+ self.assertEqual(0, len(events))
206+ # assert that other events are not ignored
207+ self.watch._process_events([(1, 'test')])
208+ self.assertEqual(1, len(events))
209
210=== modified file 'ubuntuone/platform/windows/filesystem_notifications.py'
211--- ubuntuone/platform/windows/filesystem_notifications.py 2011-07-28 19:04:19 +0000
212+++ ubuntuone/platform/windows/filesystem_notifications.py 2011-07-29 13:35:16 +0000
213@@ -122,7 +122,7 @@
214 """Implement the same functions as pyinotify.Watch."""
215
216 def __init__(self, watch_descriptor, path, mask, auto_add, processor,
217- exclude_filter=None, buf_size=8192):
218+ buf_size=8192):
219 super(Watch, self).__init__()
220 self.log = logging.getLogger('ubuntuone.SyncDaemon.platform.windows.' +
221 'filesystem_notifications.Watch')
222@@ -135,7 +135,7 @@
223 self._watching = False
224 self._descriptor = watch_descriptor
225 self._auto_add = auto_add
226- self.exclude_filter = exclude_filter
227+ self._ignore_paths = []
228 self._cookie = None
229 self._source_pathname = None
230 self._process_thread = None
231@@ -144,6 +144,8 @@
232 self._subdirs = []
233 # ensure that we work with an abspath and that we can deal with
234 # long paths over 260 chars.
235+ if not path.endswith(os.path.sep):
236+ path += os.path.sep
237 self._path = os.path.abspath(path)
238 self._mask = mask
239 # this deferred is fired when the watch has started monitoring
240@@ -152,8 +154,7 @@
241
242 def _is_excluded(self, event):
243 """Return if an event is ignored."""
244- return (self.exclude_filter and self.exclude_filter(event)) or\
245- event.mask == IN_OPEN | IN_ISDIR
246+ return event.mask == IN_OPEN | IN_ISDIR
247
248 # XXX: confirm is using this decorator is correct!!! (nessita)
249 @is_valid_windows_path(path_indexes=[1])
250@@ -184,6 +185,9 @@
251 # we transform the events to be the same as the one in pyinotify
252 # and then use the proc_fun
253 for action, file_name in events:
254+ if any([file_name.startswith(path)
255+ for path in self._ignore_paths]):
256+ continue
257 # map the windows events to the pyinotify ones, tis is dirty but
258 # makes the multiplatform better, linux was first :P
259 syncdaemon_path = get_syncdaemon_valid_path(
260@@ -279,6 +283,25 @@
261
262 CloseHandle(handle)
263
264+ @is_valid_windows_path(path_indexes=[1])
265+ def ignore_path(self, path):
266+ """Add the path of the events to ignore."""
267+ if not path.endswith(os.path.sep):
268+ path += os.path.sep
269+ if path.startswith(self._path):
270+ path = path[len(self._path):]
271+ self._ignore_paths.append(path)
272+
273+ @is_valid_windows_path(path_indexes=[1])
274+ def remove_ignored_path(self, path):
275+ """Reaccept path."""
276+ if not path.endswith(os.path.sep):
277+ path += os.path.sep
278+ if path.startswith(self._path):
279+ path = path[len(self._path):]
280+ if path in self._ignore_paths:
281+ self._ignore_paths.remove(path)
282+
283 def start_watching(self):
284 """Tell the watch to start processing events."""
285 for current_child in os.listdir(self._path):
286@@ -322,7 +345,7 @@
287
288 """
289
290- def __init__(self, processor, exclude_filter=lambda path: False):
291+ def __init__(self, processor):
292 """Init the manager to keep trak of the different watches."""
293 super(WatchManager, self).__init__()
294 self._processor = processor
295@@ -331,7 +354,6 @@
296 self.log.setLevel(TRACE)
297 self._wdm = {}
298 self._wd_count = 0
299- self._exclude_filter = exclude_filter
300 self._ignored_paths = []
301
302 def stop(self):
303@@ -356,20 +378,19 @@
304 logging.error(str(e))
305
306 def _add_single_watch(self, path, mask, auto_add=False,
307- quiet=True, exclude_filter=None):
308+ quiet=True):
309 if path in self._ignored_paths:
310 # simply removed it from the filter
311 self._ignored_paths.remove(path)
312 return
313 # we need to add a new watch
314- self.log.debug('add_single_watch(%s, %s, %s, %s, %s)', path, mask,
315- auto_add, quiet, exclude_filter)
316+ self.log.debug('add_single_watch(%s, %s, %s, %s)', path, mask,
317+ auto_add, quiet)
318
319 # adjust the number of threads based on the UDFs watched
320 reactor.suggestThreadPoolSize(THREADPOOL_MAX + self._wd_count + 1)
321 self._wdm[self._wd_count] = Watch(self._wd_count, path,
322- mask, auto_add, self._processor,
323- exclude_filter=exclude_filter)
324+ mask, auto_add, self._processor)
325 d = self._wdm[self._wd_count].start_watching()
326 self._wd_count += 1
327 self.log.debug('Watch count increased to %s', self._wd_count)
328@@ -377,7 +398,7 @@
329
330 @is_valid_windows_path(path_indexes=[1])
331 def add_watch(self, path, mask, auto_add=False,
332- quiet=True, exclude_filter=None):
333+ quiet=True):
334 """Add a new path tp be watch.
335
336 The method will ensure that the path is not already present.
337@@ -387,8 +408,7 @@
338 return defer.fail(e)
339 if self.get_wd(path) is None:
340 self.log.debug('Adding single watch on %r', path)
341- return self._add_single_watch(path, mask, auto_add, quiet,
342- exclude_filter)
343+ return self._add_single_watch(path, mask, auto_add, quiet)
344 else:
345 self.log.debug('Watch already exists on %r', path)
346 return defer.succeed(False)
347@@ -400,6 +420,8 @@
348 @is_valid_windows_path(path_indexes=[1])
349 def get_wd(self, path):
350 """Return the watcher that is used to watch the given path."""
351+ if not path.endswith(os.path.sep):
352+ path = path + os.path.sep
353 for current_wd in self._wdm:
354 watch_path = self._wdm[current_wd].path
355 if ((watch_path == path or (
356@@ -429,23 +451,8 @@
357 """Remove a watch to the given path."""
358 wd = self.get_wd(path)
359 if wd is not None:
360- self.log.debug('Adding exclude filter for "%s"', path)
361- # we have a watch that contains the path as a child path
362- if not path in self._ignored_paths:
363- self._ignored_paths.append(path)
364-
365- def ignore_path(event):
366- """Ignore an event if it has a given path."""
367- for path in self._ignored_paths:
368- if path in event.pathname:
369- return True
370- return False
371-
372- # FIXME: This assumes that we do not have other function
373- # which in our usecase is correct, but what is we move this
374- # to other project?!? Maybe using the manager
375- # exclude_filter is better
376- self._wdm[wd].exclude_filter = ignore_path
377+ self.log.debug('Adding exclude filter for %r', path)
378+ self._wdm[wd].ignore_path(path)
379
380
381 class NotifyProcessor(ProcessEvent):

Subscribers

People subscribed via source and target branches