(original) (raw)
When trying to decide whether or not a given file needs to be recompiled, the inode creation time should be taken into account along with the file modification time. Scenario: Suppose you have three times, A < B < C < D. At time A, you package version 1 of foo.py. At time B, you package version 2. At time C you install version 1 onto some system, and byte-compile it for all users. Therefore foo.py has mtime A and ctime C, and foo.pyc has both mtime C. At time D you delete foo.py from version 1 and install version 2. Then you byte-compile it without force. At that time, foo.py has mtime B (because that was when it was packaged) but ctime D (because that was when the file was created). foo.pyc has mtime C (because that was when it was last modified). The current comparison compares only mtimes, sees C > B, and skips foo.py. With this patch in place, it will check for C > max(B, D), which is not the case, and thus recompile foo.c. In other words, max(st_mtime, st_ctime) can be interpreted as the last time a file at a given path was changed, either through modification of its contents (mtime) or deletion followed by recreation (ctime). Installation systems that overwrite files without deleting them before still are in the same trouble as before, but all others will benefit from this. References: http://bugs.python.org/issue5128 http://bugs.gentoo.org/256953 2009-02-02 Martin von Gagern Index: Lib/compileall.py =================================================================== --- Lib/compileall.py (revision 69204) +++ Lib/compileall.py (working copy) @@ -55,7 +55,8 @@ head, tail = name[:-3], name[-3:] if tail == '.py': cfile = fullname + (__debug__ and 'c' or 'o') - ftime = os.stat(fullname).st_mtime + fstat = os.stat(fullname) + ftime = max(fstat.st_mtime, fstat.st_ctime) try: ctime = os.stat(cfile).st_mtime except os.error: ctime = 0 if (ctime > ftime) and not force: continue