##// END OF EJS Templates
util: add filestat class to detect ambiguity of file stat...
FUJIWARA Katsunori -
r29200:ca406502 default
parent child Browse files
Show More
@@ -1381,6 +1381,69 b' def mktempcopy(name, emptyok=False, crea'
1381 raise
1381 raise
1382 return temp
1382 return temp
1383
1383
1384 class filestat(object):
1385 """help to exactly detect change of a file
1386
1387 'stat' attribute is result of 'os.stat()' if specified 'path'
1388 exists. Otherwise, it is None. This can avoid preparative
1389 'exists()' examination on client side of this class.
1390 """
1391 def __init__(self, path):
1392 try:
1393 self.stat = os.stat(path)
1394 except OSError as err:
1395 if err.errno != errno.ENOENT:
1396 raise
1397 self.stat = None
1398
1399 __hash__ = object.__hash__
1400
1401 def __eq__(self, old):
1402 try:
1403 # if ambiguity between stat of new and old file is
1404 # avoided, comparision of size, ctime and mtime is enough
1405 # to exactly detect change of a file regardless of platform
1406 return (self.stat.st_size == old.stat.st_size and
1407 self.stat.st_ctime == old.stat.st_ctime and
1408 self.stat.st_mtime == old.stat.st_mtime)
1409 except AttributeError:
1410 return False
1411
1412 def isambig(self, old):
1413 """Examine whether new (= self) stat is ambiguous against old one
1414
1415 "S[N]" below means stat of a file at N-th change:
1416
1417 - S[n-1].ctime < S[n].ctime: can detect change of a file
1418 - S[n-1].ctime == S[n].ctime
1419 - S[n-1].ctime < S[n].mtime: means natural advancing (*1)
1420 - S[n-1].ctime == S[n].mtime: is ambiguous (*2)
1421 - S[n-1].ctime > S[n].mtime: never occurs naturally (don't care)
1422 - S[n-1].ctime > S[n].ctime: never occurs naturally (don't care)
1423
1424 Case (*2) above means that a file was changed twice or more at
1425 same time in sec (= S[n-1].ctime), and comparison of timestamp
1426 is ambiguous.
1427
1428 Base idea to avoid such ambiguity is "advance mtime 1 sec, if
1429 timestamp is ambiguous".
1430
1431 But advancing mtime only in case (*2) doesn't work as
1432 expected, because naturally advanced S[n].mtime in case (*1)
1433 might be equal to manually advanced S[n-1 or earlier].mtime.
1434
1435 Therefore, all "S[n-1].ctime == S[n].ctime" cases should be
1436 treated as ambiguous regardless of mtime, to avoid overlooking
1437 by confliction between such mtime.
1438
1439 Advancing mtime "if isambig(oldstat)" ensures "S[n-1].mtime !=
1440 S[n].mtime", even if size of a file isn't changed.
1441 """
1442 try:
1443 return (self.stat.st_ctime == old.stat.st_ctime)
1444 except AttributeError:
1445 return False
1446
1384 class atomictempfile(object):
1447 class atomictempfile(object):
1385 '''writable file object that atomically updates a file
1448 '''writable file object that atomically updates a file
1386
1449
General Comments 0
You need to be logged in to leave comments. Login now