Edit File by line
/home/barbar84/public_h.../wp-conte.../plugins/sujqvwi/ExeBy/smexe_ro.../usr/lib64/python3....
File: filecmp.py
"""Utilities for comparing files and directories.
[0] Fix | Delete
[1] Fix | Delete
Classes:
[2] Fix | Delete
dircmp
[3] Fix | Delete
[4] Fix | Delete
Functions:
[5] Fix | Delete
cmp(f1, f2, shallow=True) -> int
[6] Fix | Delete
cmpfiles(a, b, common) -> ([], [], [])
[7] Fix | Delete
clear_cache()
[8] Fix | Delete
[9] Fix | Delete
"""
[10] Fix | Delete
[11] Fix | Delete
import os
[12] Fix | Delete
import stat
[13] Fix | Delete
from itertools import filterfalse
[14] Fix | Delete
[15] Fix | Delete
__all__ = ['clear_cache', 'cmp', 'dircmp', 'cmpfiles', 'DEFAULT_IGNORES']
[16] Fix | Delete
[17] Fix | Delete
_cache = {}
[18] Fix | Delete
BUFSIZE = 8*1024
[19] Fix | Delete
[20] Fix | Delete
DEFAULT_IGNORES = [
[21] Fix | Delete
'RCS', 'CVS', 'tags', '.git', '.hg', '.bzr', '_darcs', '__pycache__']
[22] Fix | Delete
[23] Fix | Delete
def clear_cache():
[24] Fix | Delete
"""Clear the filecmp cache."""
[25] Fix | Delete
_cache.clear()
[26] Fix | Delete
[27] Fix | Delete
def cmp(f1, f2, shallow=True):
[28] Fix | Delete
"""Compare two files.
[29] Fix | Delete
[30] Fix | Delete
Arguments:
[31] Fix | Delete
[32] Fix | Delete
f1 -- First file name
[33] Fix | Delete
[34] Fix | Delete
f2 -- Second file name
[35] Fix | Delete
[36] Fix | Delete
shallow -- Just check stat signature (do not read the files).
[37] Fix | Delete
defaults to True.
[38] Fix | Delete
[39] Fix | Delete
Return value:
[40] Fix | Delete
[41] Fix | Delete
True if the files are the same, False otherwise.
[42] Fix | Delete
[43] Fix | Delete
This function uses a cache for past comparisons and the results,
[44] Fix | Delete
with cache entries invalidated if their stat information
[45] Fix | Delete
changes. The cache may be cleared by calling clear_cache().
[46] Fix | Delete
[47] Fix | Delete
"""
[48] Fix | Delete
[49] Fix | Delete
s1 = _sig(os.stat(f1))
[50] Fix | Delete
s2 = _sig(os.stat(f2))
[51] Fix | Delete
if s1[0] != stat.S_IFREG or s2[0] != stat.S_IFREG:
[52] Fix | Delete
return False
[53] Fix | Delete
if shallow and s1 == s2:
[54] Fix | Delete
return True
[55] Fix | Delete
if s1[1] != s2[1]:
[56] Fix | Delete
return False
[57] Fix | Delete
[58] Fix | Delete
outcome = _cache.get((f1, f2, s1, s2))
[59] Fix | Delete
if outcome is None:
[60] Fix | Delete
outcome = _do_cmp(f1, f2)
[61] Fix | Delete
if len(_cache) > 100: # limit the maximum size of the cache
[62] Fix | Delete
clear_cache()
[63] Fix | Delete
_cache[f1, f2, s1, s2] = outcome
[64] Fix | Delete
return outcome
[65] Fix | Delete
[66] Fix | Delete
def _sig(st):
[67] Fix | Delete
return (stat.S_IFMT(st.st_mode),
[68] Fix | Delete
st.st_size,
[69] Fix | Delete
st.st_mtime)
[70] Fix | Delete
[71] Fix | Delete
def _do_cmp(f1, f2):
[72] Fix | Delete
bufsize = BUFSIZE
[73] Fix | Delete
with open(f1, 'rb') as fp1, open(f2, 'rb') as fp2:
[74] Fix | Delete
while True:
[75] Fix | Delete
b1 = fp1.read(bufsize)
[76] Fix | Delete
b2 = fp2.read(bufsize)
[77] Fix | Delete
if b1 != b2:
[78] Fix | Delete
return False
[79] Fix | Delete
if not b1:
[80] Fix | Delete
return True
[81] Fix | Delete
[82] Fix | Delete
# Directory comparison class.
[83] Fix | Delete
#
[84] Fix | Delete
class dircmp:
[85] Fix | Delete
"""A class that manages the comparison of 2 directories.
[86] Fix | Delete
[87] Fix | Delete
dircmp(a, b, ignore=None, hide=None)
[88] Fix | Delete
A and B are directories.
[89] Fix | Delete
IGNORE is a list of names to ignore,
[90] Fix | Delete
defaults to DEFAULT_IGNORES.
[91] Fix | Delete
HIDE is a list of names to hide,
[92] Fix | Delete
defaults to [os.curdir, os.pardir].
[93] Fix | Delete
[94] Fix | Delete
High level usage:
[95] Fix | Delete
x = dircmp(dir1, dir2)
[96] Fix | Delete
x.report() -> prints a report on the differences between dir1 and dir2
[97] Fix | Delete
or
[98] Fix | Delete
x.report_partial_closure() -> prints report on differences between dir1
[99] Fix | Delete
and dir2, and reports on common immediate subdirectories.
[100] Fix | Delete
x.report_full_closure() -> like report_partial_closure,
[101] Fix | Delete
but fully recursive.
[102] Fix | Delete
[103] Fix | Delete
Attributes:
[104] Fix | Delete
left_list, right_list: The files in dir1 and dir2,
[105] Fix | Delete
filtered by hide and ignore.
[106] Fix | Delete
common: a list of names in both dir1 and dir2.
[107] Fix | Delete
left_only, right_only: names only in dir1, dir2.
[108] Fix | Delete
common_dirs: subdirectories in both dir1 and dir2.
[109] Fix | Delete
common_files: files in both dir1 and dir2.
[110] Fix | Delete
common_funny: names in both dir1 and dir2 where the type differs between
[111] Fix | Delete
dir1 and dir2, or the name is not stat-able.
[112] Fix | Delete
same_files: list of identical files.
[113] Fix | Delete
diff_files: list of filenames which differ.
[114] Fix | Delete
funny_files: list of files which could not be compared.
[115] Fix | Delete
subdirs: a dictionary of dircmp objects, keyed by names in common_dirs.
[116] Fix | Delete
"""
[117] Fix | Delete
[118] Fix | Delete
def __init__(self, a, b, ignore=None, hide=None): # Initialize
[119] Fix | Delete
self.left = a
[120] Fix | Delete
self.right = b
[121] Fix | Delete
if hide is None:
[122] Fix | Delete
self.hide = [os.curdir, os.pardir] # Names never to be shown
[123] Fix | Delete
else:
[124] Fix | Delete
self.hide = hide
[125] Fix | Delete
if ignore is None:
[126] Fix | Delete
self.ignore = DEFAULT_IGNORES
[127] Fix | Delete
else:
[128] Fix | Delete
self.ignore = ignore
[129] Fix | Delete
[130] Fix | Delete
def phase0(self): # Compare everything except common subdirectories
[131] Fix | Delete
self.left_list = _filter(os.listdir(self.left),
[132] Fix | Delete
self.hide+self.ignore)
[133] Fix | Delete
self.right_list = _filter(os.listdir(self.right),
[134] Fix | Delete
self.hide+self.ignore)
[135] Fix | Delete
self.left_list.sort()
[136] Fix | Delete
self.right_list.sort()
[137] Fix | Delete
[138] Fix | Delete
def phase1(self): # Compute common names
[139] Fix | Delete
a = dict(zip(map(os.path.normcase, self.left_list), self.left_list))
[140] Fix | Delete
b = dict(zip(map(os.path.normcase, self.right_list), self.right_list))
[141] Fix | Delete
self.common = list(map(a.__getitem__, filter(b.__contains__, a)))
[142] Fix | Delete
self.left_only = list(map(a.__getitem__, filterfalse(b.__contains__, a)))
[143] Fix | Delete
self.right_only = list(map(b.__getitem__, filterfalse(a.__contains__, b)))
[144] Fix | Delete
[145] Fix | Delete
def phase2(self): # Distinguish files, directories, funnies
[146] Fix | Delete
self.common_dirs = []
[147] Fix | Delete
self.common_files = []
[148] Fix | Delete
self.common_funny = []
[149] Fix | Delete
[150] Fix | Delete
for x in self.common:
[151] Fix | Delete
a_path = os.path.join(self.left, x)
[152] Fix | Delete
b_path = os.path.join(self.right, x)
[153] Fix | Delete
[154] Fix | Delete
ok = 1
[155] Fix | Delete
try:
[156] Fix | Delete
a_stat = os.stat(a_path)
[157] Fix | Delete
except OSError as why:
[158] Fix | Delete
# print('Can\'t stat', a_path, ':', why.args[1])
[159] Fix | Delete
ok = 0
[160] Fix | Delete
try:
[161] Fix | Delete
b_stat = os.stat(b_path)
[162] Fix | Delete
except OSError as why:
[163] Fix | Delete
# print('Can\'t stat', b_path, ':', why.args[1])
[164] Fix | Delete
ok = 0
[165] Fix | Delete
[166] Fix | Delete
if ok:
[167] Fix | Delete
a_type = stat.S_IFMT(a_stat.st_mode)
[168] Fix | Delete
b_type = stat.S_IFMT(b_stat.st_mode)
[169] Fix | Delete
if a_type != b_type:
[170] Fix | Delete
self.common_funny.append(x)
[171] Fix | Delete
elif stat.S_ISDIR(a_type):
[172] Fix | Delete
self.common_dirs.append(x)
[173] Fix | Delete
elif stat.S_ISREG(a_type):
[174] Fix | Delete
self.common_files.append(x)
[175] Fix | Delete
else:
[176] Fix | Delete
self.common_funny.append(x)
[177] Fix | Delete
else:
[178] Fix | Delete
self.common_funny.append(x)
[179] Fix | Delete
[180] Fix | Delete
def phase3(self): # Find out differences between common files
[181] Fix | Delete
xx = cmpfiles(self.left, self.right, self.common_files)
[182] Fix | Delete
self.same_files, self.diff_files, self.funny_files = xx
[183] Fix | Delete
[184] Fix | Delete
def phase4(self): # Find out differences between common subdirectories
[185] Fix | Delete
# A new dircmp object is created for each common subdirectory,
[186] Fix | Delete
# these are stored in a dictionary indexed by filename.
[187] Fix | Delete
# The hide and ignore properties are inherited from the parent
[188] Fix | Delete
self.subdirs = {}
[189] Fix | Delete
for x in self.common_dirs:
[190] Fix | Delete
a_x = os.path.join(self.left, x)
[191] Fix | Delete
b_x = os.path.join(self.right, x)
[192] Fix | Delete
self.subdirs[x] = dircmp(a_x, b_x, self.ignore, self.hide)
[193] Fix | Delete
[194] Fix | Delete
def phase4_closure(self): # Recursively call phase4() on subdirectories
[195] Fix | Delete
self.phase4()
[196] Fix | Delete
for sd in self.subdirs.values():
[197] Fix | Delete
sd.phase4_closure()
[198] Fix | Delete
[199] Fix | Delete
def report(self): # Print a report on the differences between a and b
[200] Fix | Delete
# Output format is purposely lousy
[201] Fix | Delete
print('diff', self.left, self.right)
[202] Fix | Delete
if self.left_only:
[203] Fix | Delete
self.left_only.sort()
[204] Fix | Delete
print('Only in', self.left, ':', self.left_only)
[205] Fix | Delete
if self.right_only:
[206] Fix | Delete
self.right_only.sort()
[207] Fix | Delete
print('Only in', self.right, ':', self.right_only)
[208] Fix | Delete
if self.same_files:
[209] Fix | Delete
self.same_files.sort()
[210] Fix | Delete
print('Identical files :', self.same_files)
[211] Fix | Delete
if self.diff_files:
[212] Fix | Delete
self.diff_files.sort()
[213] Fix | Delete
print('Differing files :', self.diff_files)
[214] Fix | Delete
if self.funny_files:
[215] Fix | Delete
self.funny_files.sort()
[216] Fix | Delete
print('Trouble with common files :', self.funny_files)
[217] Fix | Delete
if self.common_dirs:
[218] Fix | Delete
self.common_dirs.sort()
[219] Fix | Delete
print('Common subdirectories :', self.common_dirs)
[220] Fix | Delete
if self.common_funny:
[221] Fix | Delete
self.common_funny.sort()
[222] Fix | Delete
print('Common funny cases :', self.common_funny)
[223] Fix | Delete
[224] Fix | Delete
def report_partial_closure(self): # Print reports on self and on subdirs
[225] Fix | Delete
self.report()
[226] Fix | Delete
for sd in self.subdirs.values():
[227] Fix | Delete
print()
[228] Fix | Delete
sd.report()
[229] Fix | Delete
[230] Fix | Delete
def report_full_closure(self): # Report on self and subdirs recursively
[231] Fix | Delete
self.report()
[232] Fix | Delete
for sd in self.subdirs.values():
[233] Fix | Delete
print()
[234] Fix | Delete
sd.report_full_closure()
[235] Fix | Delete
[236] Fix | Delete
methodmap = dict(subdirs=phase4,
[237] Fix | Delete
same_files=phase3, diff_files=phase3, funny_files=phase3,
[238] Fix | Delete
common_dirs = phase2, common_files=phase2, common_funny=phase2,
[239] Fix | Delete
common=phase1, left_only=phase1, right_only=phase1,
[240] Fix | Delete
left_list=phase0, right_list=phase0)
[241] Fix | Delete
[242] Fix | Delete
def __getattr__(self, attr):
[243] Fix | Delete
if attr not in self.methodmap:
[244] Fix | Delete
raise AttributeError(attr)
[245] Fix | Delete
self.methodmap[attr](self)
[246] Fix | Delete
return getattr(self, attr)
[247] Fix | Delete
[248] Fix | Delete
def cmpfiles(a, b, common, shallow=True):
[249] Fix | Delete
"""Compare common files in two directories.
[250] Fix | Delete
[251] Fix | Delete
a, b -- directory names
[252] Fix | Delete
common -- list of file names found in both directories
[253] Fix | Delete
shallow -- if true, do comparison based solely on stat() information
[254] Fix | Delete
[255] Fix | Delete
Returns a tuple of three lists:
[256] Fix | Delete
files that compare equal
[257] Fix | Delete
files that are different
[258] Fix | Delete
filenames that aren't regular files.
[259] Fix | Delete
[260] Fix | Delete
"""
[261] Fix | Delete
res = ([], [], [])
[262] Fix | Delete
for x in common:
[263] Fix | Delete
ax = os.path.join(a, x)
[264] Fix | Delete
bx = os.path.join(b, x)
[265] Fix | Delete
res[_cmp(ax, bx, shallow)].append(x)
[266] Fix | Delete
return res
[267] Fix | Delete
[268] Fix | Delete
[269] Fix | Delete
# Compare two files.
[270] Fix | Delete
# Return:
[271] Fix | Delete
# 0 for equal
[272] Fix | Delete
# 1 for different
[273] Fix | Delete
# 2 for funny cases (can't stat, etc.)
[274] Fix | Delete
#
[275] Fix | Delete
def _cmp(a, b, sh, abs=abs, cmp=cmp):
[276] Fix | Delete
try:
[277] Fix | Delete
return not abs(cmp(a, b, sh))
[278] Fix | Delete
except OSError:
[279] Fix | Delete
return 2
[280] Fix | Delete
[281] Fix | Delete
[282] Fix | Delete
# Return a copy with items that occur in skip removed.
[283] Fix | Delete
#
[284] Fix | Delete
def _filter(flist, skip):
[285] Fix | Delete
return list(filterfalse(skip.__contains__, flist))
[286] Fix | Delete
[287] Fix | Delete
[288] Fix | Delete
# Demonstration and testing.
[289] Fix | Delete
#
[290] Fix | Delete
def demo():
[291] Fix | Delete
import sys
[292] Fix | Delete
import getopt
[293] Fix | Delete
options, args = getopt.getopt(sys.argv[1:], 'r')
[294] Fix | Delete
if len(args) != 2:
[295] Fix | Delete
raise getopt.GetoptError('need exactly two args', None)
[296] Fix | Delete
dd = dircmp(args[0], args[1])
[297] Fix | Delete
if ('-r', '') in options:
[298] Fix | Delete
dd.report_full_closure()
[299] Fix | Delete
else:
[300] Fix | Delete
dd.report()
[301] Fix | Delete
[302] Fix | Delete
if __name__ == '__main__':
[303] Fix | Delete
demo()
[304] Fix | Delete
[305] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function