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':