Mercurial > hg
comparison hgext/inotify/server.py @ 8599:1f706b1b62f3
inotify: server: refactor updatestatus()
* Instead of one entry point, use two entry points, updatefile()
and deletefile(), both internally calling the helper function _updatestatus
* Do not rely on TypeError to detect the type of oldstatus: use isinstance
* The call updatestatus(wpath, None) in deleted() was a bit particular:
because no osstat and no newstatus was given, the newstatus was determined
using the data stored internally. To replace this exact behavior with the
new code, one would use:
root, fn = self.split(wpath)
d = self.dir(self.tree, root)
self.filedeleted(wpath, d.get(fn))
This, however, duplicates code with _updatestatus(), which led us to an
interesting question: why are we basing ourselves on repowatcher data to
update the status, where everywhere else, we are comparing against dirsate?
There is no reason to do this, which is why the new code is:
self.filedeleted(wpath, self.repo.dirstate[wpath])
Incidentally, after this, the test for issue1371 passes again.
author | Nicolas Dumazet <nicdumz.commits@gmail.com> |
---|---|
date | Sun, 24 May 2009 18:43:05 +0900 |
parents | 67f76a4463ef |
children | d46cdfcecaf1 |
comparison
equal
deleted
inserted
replaced
8557:67f76a4463ef | 8599:1f706b1b62f3 |
---|---|
248 return 'n' | 248 return 'n' |
249 if type_ == '?' and self.repo.dirstate._ignore(fn): | 249 if type_ == '?' and self.repo.dirstate._ignore(fn): |
250 return 'i' | 250 return 'i' |
251 return type_ | 251 return type_ |
252 | 252 |
253 def updatestatus(self, wfn, osstat=None, newstatus=None): | 253 def updatefile(self, wfn, osstat): |
254 ''' | |
255 update the file entry of an existing file. | |
256 | |
257 osstat: (mode, size, time) tuple, as returned by os.lstat(wfn) | |
258 ''' | |
259 | |
260 self._updatestatus(wfn, self.filestatus(wfn, osstat)) | |
261 | |
262 def deletefile(self, wfn, oldstatus): | |
263 ''' | |
264 update the entry of a file which has been deleted. | |
265 | |
266 oldstatus: char in statuskeys, status of the file before deletion | |
267 ''' | |
268 if oldstatus == 'r': | |
269 newstatus = 'r' | |
270 elif oldstatus in 'almn': | |
271 newstatus = '!' | |
272 else: | |
273 newstatus = None | |
274 | |
275 self.statcache.pop(wfn, None) | |
276 self._updatestatus(wfn, newstatus) | |
277 | |
278 def _updatestatus(self, wfn, newstatus): | |
254 ''' | 279 ''' |
255 Update the stored status of a file or directory. | 280 Update the stored status of a file or directory. |
256 | 281 |
257 osstat: (mode, size, time) tuple, as returned by os.lstat(wfn) | 282 newstatus: - char in (statuskeys + 'ni'), new status to apply. |
258 | 283 - or None, to stop tracking wfn |
259 newstatus: char in statuskeys, new status to apply. | |
260 ''' | 284 ''' |
261 if osstat: | |
262 newstatus = self.filestatus(wfn, osstat) | |
263 else: | |
264 self.statcache.pop(wfn, None) | |
265 root, fn = self.split(wfn) | 285 root, fn = self.split(wfn) |
266 d = self.dir(self.tree, root) | 286 d = self.dir(self.tree, root) |
287 | |
267 oldstatus = d.get(fn) | 288 oldstatus = d.get(fn) |
268 isdir = False | 289 # oldstatus can be either: |
269 if oldstatus: | 290 # - None : fn is new |
270 try: | 291 # - a char in statuskeys: fn is a (tracked) file |
271 if not newstatus: | 292 # - a dict: fn is a directory |
272 if oldstatus in 'almn': | 293 isdir = isinstance(oldstatus, dict) |
273 newstatus = '!' | 294 |
274 elif oldstatus == 'r': | |
275 newstatus = 'r' | |
276 except TypeError: | |
277 # oldstatus may be a dict left behind by a deleted | |
278 # directory | |
279 isdir = True | |
280 else: | |
281 if oldstatus in self.statuskeys and oldstatus != newstatus: | |
282 del self.dir(self.statustrees[oldstatus], root)[fn] | |
283 if self.ui.debugflag and oldstatus != newstatus: | 295 if self.ui.debugflag and oldstatus != newstatus: |
284 if isdir: | 296 if isdir: |
285 self.ui.note(_('status: %r dir(%d) -> %s\n') % | 297 self.ui.note(_('status: %r dir(%d) -> %s\n') % |
286 (wfn, len(oldstatus), newstatus)) | 298 (wfn, len(oldstatus), newstatus)) |
287 else: | 299 else: |
288 self.ui.note(_('status: %r %s -> %s\n') % | 300 self.ui.note(_('status: %r %s -> %s\n') % |
289 (wfn, oldstatus, newstatus)) | 301 (wfn, oldstatus, newstatus)) |
290 if not isdir: | 302 if not isdir: |
303 if oldstatus and oldstatus in self.statuskeys \ | |
304 and oldstatus != newstatus: | |
305 del self.dir(self.statustrees[oldstatus], root)[fn] | |
291 if newstatus and newstatus != 'i': | 306 if newstatus and newstatus != 'i': |
292 d[fn] = newstatus | 307 d[fn] = newstatus |
293 if newstatus in self.statuskeys: | 308 if newstatus in self.statuskeys: |
294 dd = self.dir(self.statustrees[newstatus], root) | 309 dd = self.dir(self.statustrees[newstatus], root) |
295 if oldstatus != newstatus or fn not in dd: | 310 if oldstatus != newstatus or fn not in dd: |
297 else: | 312 else: |
298 d.pop(fn, None) | 313 d.pop(fn, None) |
299 elif not newstatus: | 314 elif not newstatus: |
300 # a directory is being removed, check its contents | 315 # a directory is being removed, check its contents |
301 for subfile, b in oldstatus.copy().iteritems(): | 316 for subfile, b in oldstatus.copy().iteritems(): |
302 self.updatestatus(wfn + '/' + subfile, None) | 317 self._updatestatus(wfn + '/' + subfile, None) |
303 | 318 |
304 | 319 |
305 def check_deleted(self, key): | 320 def check_deleted(self, key): |
306 # Files that had been deleted but were present in the dirstate | 321 # Files that had been deleted but were present in the dirstate |
307 # may have vanished from the dirstate; we must clean them up. | 322 # may have vanished from the dirstate; we must clean them up. |
323 self.add_watch(join(root, d), self.mask) | 338 self.add_watch(join(root, d), self.mask) |
324 wroot = root[len(self.wprefix):] | 339 wroot = root[len(self.wprefix):] |
325 d = self.dir(self.tree, wroot) | 340 d = self.dir(self.tree, wroot) |
326 for fn in files: | 341 for fn in files: |
327 wfn = join(wroot, fn) | 342 wfn = join(wroot, fn) |
328 self.updatestatus(wfn, self.getstat(wfn)) | 343 self.updatefile(wfn, self.getstat(wfn)) |
329 ds.pop(wfn, None) | 344 ds.pop(wfn, None) |
330 wtopdir = topdir | 345 wtopdir = topdir |
331 if wtopdir and wtopdir[-1] != '/': | 346 if wtopdir and wtopdir[-1] != '/': |
332 wtopdir += '/' | 347 wtopdir += '/' |
333 for wfn, state in ds.iteritems(): | 348 for wfn, state in ds.iteritems(): |
335 continue | 350 continue |
336 try: | 351 try: |
337 st = self.stat(wfn) | 352 st = self.stat(wfn) |
338 except OSError: | 353 except OSError: |
339 status = state[0] | 354 status = state[0] |
340 self.updatestatus(wfn, None, newstatus=status) | 355 self.deletefile(wfn, status) |
341 else: | 356 else: |
342 self.updatestatus(wfn, st) | 357 self.updatefile(wfn, st) |
343 self.check_deleted('!') | 358 self.check_deleted('!') |
344 self.check_deleted('r') | 359 self.check_deleted('r') |
345 | 360 |
346 def check_dirstate(self): | 361 def check_dirstate(self): |
347 ds_info = self.dirstate_info() | 362 ds_info = self.dirstate_info() |
407 if wpath == '.hgignore': | 422 if wpath == '.hgignore': |
408 self.update_hgignore() | 423 self.update_hgignore() |
409 try: | 424 try: |
410 st = self.stat(wpath) | 425 st = self.stat(wpath) |
411 if stat.S_ISREG(st[0]): | 426 if stat.S_ISREG(st[0]): |
412 self.updatestatus(wpath, st) | 427 self.updatefile(wpath, st) |
413 except OSError: | 428 except OSError: |
414 pass | 429 pass |
415 | 430 |
416 def modified(self, wpath): | 431 def modified(self, wpath): |
417 if wpath == '.hgignore': | 432 if wpath == '.hgignore': |
418 self.update_hgignore() | 433 self.update_hgignore() |
419 try: | 434 try: |
420 st = self.stat(wpath) | 435 st = self.stat(wpath) |
421 if stat.S_ISREG(st[0]): | 436 if stat.S_ISREG(st[0]): |
422 if self.repo.dirstate[wpath] in 'lmn': | 437 if self.repo.dirstate[wpath] in 'lmn': |
423 self.updatestatus(wpath, st) | 438 self.updatefile(wpath, st) |
424 except OSError: | 439 except OSError: |
425 pass | 440 pass |
426 | 441 |
427 def deleted(self, wpath): | 442 def deleted(self, wpath): |
428 if wpath == '.hgignore': | 443 if wpath == '.hgignore': |
430 elif wpath.startswith('.hg/'): | 445 elif wpath.startswith('.hg/'): |
431 if wpath == '.hg/wlock': | 446 if wpath == '.hg/wlock': |
432 self.check_dirstate() | 447 self.check_dirstate() |
433 return | 448 return |
434 | 449 |
435 self.updatestatus(wpath, None) | 450 self.deletefile(wpath, self.repo.dirstate[wpath]) |
436 | 451 |
437 def schedule_work(self, wpath, evt): | 452 def schedule_work(self, wpath, evt): |
438 prev = self.eventq.setdefault(wpath, []) | 453 prev = self.eventq.setdefault(wpath, []) |
439 try: | 454 try: |
440 if prev and evt == 'm' and prev[-1] in 'cm': | 455 if prev and evt == 'm' and prev[-1] in 'cm': |