X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scripts%2Fbuild%2Foutput-distance.py;h=625ce12a1e3f1ab70db53797457ddc400e2472a5;hb=HEAD;hp=6b63e79f90cccf3c12aa7d769c12a26d73903015;hpb=daf323ec5bc8a09f80ea54c63f1cfedb310d2aaa;p=lilypond.git diff --git a/scripts/build/output-distance.py b/scripts/build/output-distance.py old mode 100644 new mode 100755 index 6b63e79f90..625ce12a1e --- a/scripts/build/output-distance.py +++ b/scripts/build/output-distance.py @@ -3,6 +3,9 @@ import sys import optparse import os import math +import re + +import cgi ## so we can call directly as scripts/build/output-distance.py me_path = os.path.abspath (os.path.split (sys.argv[0])[0]) @@ -50,8 +53,7 @@ def system (c): raise Exception ("failed") return -def shorten_string (s): - threshold = 15 +def shorten_string (s, threshold = 15): if len (s) > 2*threshold: s = s[:threshold] + '..' + s[-threshold:] return s @@ -87,7 +89,7 @@ def compare_png_images (old, new, dest_dir): system ('convert -depth 8 -crop %dx%d+0+0 %s %s/crop1.png' % (dims + (old, dir))) system ('convert -depth 8 -crop %dx%d+0+0 %s %s/crop2.png' % (dims + (new, dir))) - system ('compare -depth 8 %(dir)s/crop1.png %(dir)s/crop2.png %(dir)s/diff.png' % locals ()) + system1 ('compare -depth 8 -dissimilarity-threshold 1 %(dir)s/crop1.png %(dir)s/crop2.png %(dir)s/diff.png' % locals ()) system ("convert -depth 8 %(dir)s/diff.png -blur 0x3 -negate -channel alpha,blue -type TrueColorMatte -fx 'intensity' %(dir)s/matte.png" % locals ()) @@ -313,12 +315,17 @@ class SystemLink: self.orphan_count (), self.geometric_distance ()) +def scheme_float (s) : + if 'nan' not in s : + return float(s) + return float(s.split('.')[0]) + def read_signature_file (name): print 'reading', name entries = open (name).read ().split ('\n') def string_to_tup (s): - return tuple (map (float, s.split (' '))) + return tuple (map (scheme_float, s.split (' '))) def string_to_entry (s): fields = s.split('@') @@ -369,12 +376,18 @@ class FileLink: return '' + def directories (self): + return map (os.path.dirname, self.file_names) + def name (self): base = os.path.basename (self.file_names[1]) base = os.path.splitext (base)[0] base = hash_to_original_name.get (base, base) base = os.path.splitext (base)[0] - return base + return os.path.join (self.prefix (), base) + + def prefix (self): + return os.path.dirname (os.path.commonprefix (self.file_names)) def extension (self): return os.path.splitext (self.file_names[1])[1] @@ -451,7 +464,7 @@ class GitFileCompareLink (FileCompareLink): str = '\n'.join ([l[:80] for l in str.split ('\n')]) - str = '
%s
' % str + str = '
%s
' % cgi.escape (str) return str def calc_distance (self): @@ -463,11 +476,22 @@ class GitFileCompareLink (FileCompareLink): return d +snippet_fn_re = re.compile (r"`\./([0-9a-f]{2}/lily-[0-9a-f]{8}).eps'"); class TextFileCompareLink (FileCompareLink): def calc_distance (self): import difflib - diff = difflib.unified_diff (self.contents[0].strip().split ('\n'), - self.contents[1].strip().split ('\n'), + # Extract the old and the new hashed snippet names from the log file + # and replace the old by the new, so file name changes don't show + # up as log differences... + cont0 = self.contents[0].strip(); + cont1 = self.contents[1].strip(); + m0 = re.search (snippet_fn_re, cont0); + m1 = re.search (snippet_fn_re, cont1); + if (m0 and m1 and (m0.group(1) != m1.group(1))): + cont0 = cont0.replace (m0.group(1), m1.group(1)); + + diff = difflib.unified_diff (cont0.split ('\n'), + cont1.split ('\n'), fromfiledate = self.file_names[0], tofiledate = self.file_names[1] ) @@ -481,7 +505,7 @@ class TextFileCompareLink (FileCompareLink): str = '' if oldnew == 1: str = '\n'.join ([d.replace ('\n','') for d in self.diff_lines]) - str = '
%s
' % str + str = '
%s
' % cgi.escape (str) return str class LogFileCompareLink (TextFileCompareLink): @@ -504,7 +528,7 @@ class ProfileFileLink (FileCompareLink): str += '%-8s: %8d (%5.3f)\n' % (k, int (self.results[oldnew][k]), self.get_ratio (k)) - return '
%s
' % str + return '
%s
' % cgi.escape (str) def get_ratio (self, key): (v1,v2) = (self.results[0].get (key, -1), @@ -618,6 +642,7 @@ class SignatureFileLink (FileLink): cmd = ('gs -sDEVICE=png16m -dGraphicsAlphaBits=4 -dTextAlphaBits=4 ' ' %(data_option)s ' ' -r101 ' + ' -dAutoRotatePages=/None ' ' -sOutputFile=%(outfile)s -dNOSAFER -dEPSCrop -q -dNOPAUSE ' ' %(infile)s -c quit ') % locals () @@ -749,7 +774,6 @@ class SignatureFileLink (FileLink): # Files/directories import glob -import re def compare_signature_files (f1, f2): s1 = read_signature_file (f1) @@ -804,13 +828,25 @@ class ComparisonData: re.sub (r'\\sourcefilename "([^"]+)"', note_original, open (sf).read ()) else: - print 'no source for', val + print 'no source for', val.file_names[1] def compare_trees (self, dir1, dir2): self.compare_directories (dir1, dir2) - (root, dirs, files) = os.walk (dir1).next () + try: + (root, dirs, files) = os.walk (dir1).next () + except StopIteration: + if dir1.endswith("-baseline"): + sys.stderr.write("Failed to walk through %s. This can be caused by forgetting to run make test-baseline.\n" % dir1) + else: + sys.stderr.write("Failed to walk through %s; please check it exists.\n" % dir1) + sys.exit(1) + for d in dirs: + # don't walk the share folders + if d.startswith("share"): + continue + d1 = os.path.join (dir1, d) d2 = os.path.join (dir2, d) @@ -856,14 +892,18 @@ class ComparisonData: self.compare_general_files (klasses[ext], f1, f2) def compare_general_files (self, klass, f1, f2): + prefix = os.path.commonprefix ([f1, f2]) name = os.path.split (f1)[1] + name = os.path.join (prefix, name) file_link = klass (f1, f2) self.file_links[name] = file_link def compare_signature_files (self, f1, f2): + prefix = os.path.commonprefix ([f1, f2]) name = os.path.split (f1)[1] name = re.sub ('-[0-9]+.signature', '', name) + name = os.path.join (prefix, name) file_link = None try: @@ -916,42 +956,84 @@ class ComparisonData: out.write ('%d below threshold\n' % len (below)) out.write ('%d unchanged\n' % len (unchanged)) - def create_text_result_page (self, dir1, dir2, dest_dir, threshold): + def create_text_result_page (self, dest_dir, threshold): self.write_text_result_page (dest_dir + '/index.txt', threshold) - def create_html_result_page (self, dir1, dir2, dest_dir, threshold): - dir1 = dir1.replace ('//', '/') - dir2 = dir2.replace ('//', '/') - + def create_html_result_page (self, dest_dir, threshold): (changed, below, unchanged) = self.thresholded_results (threshold) - - html = '' - old_prefix = os.path.split (dir1)[1] - for link in changed: - html += link.html_record_string (dest_dir) - - - short_dir1 = shorten_string (dir1) - short_dir2 = shorten_string (dir2) - html = ''' - + header_row = ''' -%(html)s -
distance %(short_dir1)s %(short_dir2)s
-''' % locals() +''' - html += ('

') + table_rows = '' + old_prefix = None + for link in changed: + this_prefix = link.prefix () + if (old_prefix != this_prefix): + old_prefix = this_prefix + short_dir1 = shorten_string (link.directories ()[0], 30) + short_dir2 = shorten_string (link.directories ()[1], 30) + table_rows += header_row % locals() + table_rows += link.html_record_string (dest_dir) + + summary = '' below_count = len (below) if below_count: - html += ('

%d below threshold

' % below_count) + summary += '

%d below threshold

' % below_count + + summary += '

%d unchanged

' % len (unchanged) + + me = sys.argv[0] + + html = ''' + +LilyPond regression test results + + + + +

+ click to filter rows by type: + ly / + profiling / + signature / + midi / + log / + gittxt / + reset to all +

+ +
- html += ('

%d unchanged

' % len (unchanged)) +%(summary)s + +
+ + +%(table_rows)s +
+ +''' % locals() dest_file = dest_dir + '/index.html' open_write_file (dest_file).write (html) @@ -964,20 +1046,20 @@ class ComparisonData: def print_results (self, threshold): self.write_text_result_page ('', threshold) -def compare_trees (dir1, dir2, dest_dir, threshold): +def compare_tree_pairs (tree_pairs, dest_dir, threshold): data = ComparisonData () - data.compare_trees (dir1, dir2) + for dir1, dir2 in tree_pairs: + data.compare_trees (dir1, dir2) data.read_sources () - data.print_results (threshold) if os.path.isdir (dest_dir): system ('rm -rf %s '% dest_dir) data.write_changed (dest_dir, threshold) - data.create_html_result_page (dir1, dir2, dest_dir, threshold) - data.create_text_result_page (dir1, dir2, dest_dir, threshold) + data.create_html_result_page (dest_dir, threshold) + data.create_text_result_page (dest_dir, threshold) ################################################################ # TESTING @@ -1008,13 +1090,19 @@ def system (x): stat = os.system (x) assert stat == 0 +def system1 (x): +# Allow exit status 0 and 1 + print 'invoking', x + stat = os.system (x) + assert (stat == 0) or (stat == 256) # This return value convention is sick. + def test_paired_files (): print paired_files (os.environ["HOME"] + "/src/lilypond/scripts/", os.environ["HOME"] + "/src/lilypond-stable/scripts/build/", '*.py') -def test_compare_trees (): +def test_compare_tree_pairs (): system ('rm -rf dir1 dir2') system ('mkdir dir1 dir2') system ('cp 20{-*.signature,.ly,.png,.eps,.log,.profile} dir1') @@ -1059,7 +1147,7 @@ def test_compare_trees (): system ('cp 19multipage.log dir1/log-differ.log') system ('cp 19multipage.log dir2/log-differ.log && echo different >> dir2/log-differ.log && echo different >> dir2/log-differ.log') - compare_trees ('dir1', 'dir2', 'compare-dir1dir2', options.threshold) + compare_tree_pairs (['dir1', 'dir2'], 'compare-dir1dir2', options.threshold) def test_basic_compare (): @@ -1184,14 +1272,14 @@ def run_tests (): if do_clean: test_basic_compare () - test_compare_trees () + test_compare_tree_pairs () ################################################################ # def main (): p = optparse.OptionParser ("output-distance - compare LilyPond formatting runs") - p.usage = 'output-distance.py [options] tree1 tree2' + p.usage = 'output-distance.py [options] tree1 tree2 [tree3 tree4]...' p.add_option ('', '--test-self', dest="run_test", @@ -1246,17 +1334,17 @@ def main (): run_tests () sys.exit (0) - if len (args) != 2: - p.print_usage() + if len (args) % 2 == 1: + p.print_usage () sys.exit (2) - name = options.output_dir - if not name: - name = args[0].replace ('/', '') - name = os.path.join (args[1], 'compare-' + shorten_string (name)) + out = options.output_dir + if not out: + out = args[0].replace ('/', '') + out = os.path.join (args[1], 'compare-' + shorten_string (out)) - compare_trees (args[0], args[1], name, options.threshold) + compare_tree_pairs (zip (args[0::2], args[1::2]), out, options.threshold) if __name__ == '__main__': - main() + main ()