elif tag == "Filtering":
self.filtering = value
# Read file properties
- self.trees = {}
+ self.trees = []
while 1:
line = self.fp.readline()
if not line or line == '%%\n':
break
(tree, properties) = line.split(":")
- self.trees[tree] = {}
+ propdict = {}
for assignment in properties.split(", "):
(property, value) = assignment.split("=")
- self.trees[tree][property.strip()] = int(value)
+ propdict[property.strip()] = int(value)
+ self.trees.append([tree, propdict])
self.cliques = []
# Reading the clique data is slow, so we only do it
# on demand.
filtered.append(clique)
break
else:
- properties = self.trees[file.split("/")[0]]
+ for (treename, properties) in self.trees:
+ if treename == file.split("/")[0]:
+ break
properties['matches'] -= 1
properties['matchlines'] -= end - start + 1
self.cliques = filtered
self.matches = len(filtered)
- def metadump(self, fp=sys.stdout, divider="%%\n", fmt=None):
+ def metadump(self, fp=sys.stdout, divider="%%\n", fmt=None, moredict={}):
"Dump the header in a canonical format."
+ fp.write("Filtering: %s\n" % self.filtering)
fp.write("Filter-Program: filterator 1.0\n")
fp.write("Hash-Method: RXOR\n")
+ fp.write("Matches: %d\n" % self.matches)
if self.merge_program:
fp.write("Merge-Program: %s\n" % self.merge_program)
fp.write("Normalization: %s\n" % self.normalization)
fp.write("Shred-Size: %d\n" % self.shredsize)
- fp.write("Filtering: %s\n" % self.filtering)
+ for (key, value) in moredict.items():
+ fp.write("%s: %d\n" % (key, value))
fp.write(divider)
- for tree in self.trees:
- rep = tree + ":"
- for (key, value) in self.trees[tree].items():
- rep += " %s=%s," % (key, value)
+ for (treename, properties) in self.trees:
+ rep = treename + ":"
+ keys = properties.keys()
+ keys.sort()
+ for key in keys:
+ rep += " %s=%s," % (key, properties[key])
fp.write(rep[:-1] + "\n")
fp.write(divider)
if fmt:
for clique in self.cliques:
- for (file, start, end) in clique:
- fp.write(fmt(file, start, end, self.files[file]))
- fp.write(divider)
+ fp.write(fmt(clique))
def preen(self):
"Fix the file properties of this report."
matches = {}
matchlines = {}
- for tree in self.trees:
- matches[tree] = matchlines[tree] = 0
+ for (treename, dummy) in self.trees:
+ matches[treename] = matchlines[treename] = 0
for clique in self.cliques:
firstmatch = {}
- for tree in self.trees:
- firstmatch[tree] = 0
+ for (treename, dummy) in self.trees:
+ firstmatch[treename] = 0
for (file, start, end) in clique:
- properties = self.trees[file.split("/")[0]]
- if not tree in firstmatch:
+ for (treename, properties) in self.trees:
+ if treename == file.split("/")[0]:
+ break
+ if not treename in firstmatch:
properties['matches'] += 1
firstmatch[tree] = True
properties['matchlines'] += end - start + 1
self.matches = len(self.cliques)
+ def cliquedump(self, clique):
+ "Dump a clique in a form identical to the input one."
+ rep = ""
+ for (file, start, end) in clique:
+ rep += "%s:%d:%d:%d\n" % (file, start, end, self.files[file])
+ rep += "%%\n"
+ return rep
+
def dump(self, fp):
"Dump in SCF-B format."
self.preen()
fp.write("#SCF-B 2.0\n")
- self.metadump(fp=fp, divider="%%\n",
- fmt=lambda f,s,e, z: "%s:%d:%d:%d\n" % (f,s,e,z))
+ self.metadump(fp=fp, fmt=self.cliquedump)
# Property flags
C_CODE = 0x01
#
import sys, comparator, re
-def report_common(state):
- "Generate a report on common code."
- print "Filter-Program: filterator 1.0"
- print "Hash-Method: RXOR"
- if state.merge_program:
- print "Merge-Program:", state.merge_program
- print "Normalization:", state.normalization
- print "Shred-Size: %d" % state.shredsize
- if minsize:
- print "Minimum-Size: %d" % minsize
- print 75 * '-'
- for tree in state.trees:
- rep = tree + ":"
- for (key, value) in state.trees[tree].items():
- rep += " %s=%s," % (key, value)
- sys.stdout.write(rep[:-1] + "\n")
- print 75 * '-'
- state.read_matches()
- for clique in state.cliques:
- (file, start, end, text) = state.extract_text(clique)
- if start == 1 and end == state.files[file]:
- print "%% %s:%d-%d: entire (%d matches)" % \
- (file, start, end, len(clique))
- else:
- print "%% %s:%d-%d: (%d matches)" % \
- (file, start, end, len(clique))
- sys.stdout.write(text)
+def reporthook(clique):
+ rep = ""
+ (file, start, end, text) = state.extract_text(clique)
+ if start == 1 and end == state.files[file]:
+ rep += "%% %s:%d-%d: entire (%d matches)" % \
+ (file, start, end, len(clique))
+ else:
+ rep += "%% %s:%d-%d: (%d matches)" % \
+ (file, start, end, len(clique))
+ rep += text
+ return rep
if __name__ == '__main__':
# Main line begins here
if opt == '-d':
dir = val
elif opt == '-f':
- filter = val
+ filter = re.compile(val)
elif opt == '-m':
minsize = int(val)
elif opt == '-n':
try:
state = comparator.CommonReport(sys.stdin, dir)
if minsize:
- state.filter_by_size(minsize)
+ state.cliquefilter(lambda file,start,end: end-start+1 >= minsize)
if filter:
- state.filter_by_filename(re.compile(filter))
+ state.cliquefilter(lambda file, start, end: filter.search(file))
try:
if expand:
- report_common(state)
+ state.metadump(sys.stdout, 75 * '-', reporthook, {"Minimum-Size":minsize})
else:
state.dump(sys.stdout)
except (KeyboardInterrupt, IOError):