X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=buildscripts%2Foutput-distance.py;h=ec8b5d9e10a769f2a907282d9885997a159c7902;hb=1c4458de37e468a5d4fe023a34a5bcb05bf24aad;hp=7c7a914d567dd23a4426c5d8e1c3b77f678b58f3;hpb=11376d6e9bc77bbf858086500fcb848a5540748c;p=lilypond.git diff --git a/buildscripts/output-distance.py b/buildscripts/output-distance.py index 7c7a914d56..ec8b5d9e10 100644 --- a/buildscripts/output-distance.py +++ b/buildscripts/output-distance.py @@ -17,7 +17,13 @@ INFTY = 1e6 OUTPUT_EXPRESSION_PENALTY = 1 ORPHAN_GROB_PENALTY = 1 -inspect_max_count = 0 +options = None + +def shorten_string (s): + threshold = 15 + if len (s) > 2*threshold: + s = s[:threshold] + '..' + s[-threshold:] + return s def max_distance (x1, x2): dist = 0.0 @@ -268,14 +274,107 @@ def read_signature_file (name): ################################################################ # different systems of a .ly file. +def read_pipe (c): + print 'pipe' , c + return os.popen (c).read () + +def system (c): + print 'system' , c + s = os.system (c) + if s : + raise Exception ("failed") + return + +def compare_png_images (old, new, dir): + def png_dims (f): + m = re.search ('([0-9]+) x ([0-9]+)', read_pipe ('file %s' % f)) + + return tuple (map (int, m.groups ())) + + dest = os.path.join (dir, new.replace ('.png', '.compare.jpeg')) + try: + dims1 = png_dims (old) + dims2 = png_dims (new) + except AttributeError: + ## hmmm. what to do? + system ('touch %(dest)s' % locals ()) + return + + dims = (min (dims1[0], dims2[0]), + min (dims1[1], dims2[1])) + + system ('convert -depth 8 -crop %dx%d+0+0 %s crop1.png' % (dims + (old,))) + system ('convert -depth 8 -crop %dx%d+0+0 %s crop2.png' % (dims + (new,))) + + system ('compare -depth 8 crop1.png crop2.png diff.png') + + system ("convert -depth 8 diff.png -blur 0x3 -negate -channel alpha,blue -type TrueColorMatte -fx 'intensity' matte.png") + + system ("composite -quality 65 matte.png %(new)s %(dest)s" % locals ()) class FileLink: + def text_record_string (self): + return '%-30f %-20s\n' % (self.distance (), + self.name ()) + def distance (self): + return 0.0 + + def name (self): + return '' + + def link_files_for_html (self, old_dir, new_dir, dest_dir): + pass + + def write_html_system_details (self, dir1, dir2, dest_dir): + pass + + def html_record_string (self, old_dir, new_dir): + return '' + +class MidiFileLink (FileLink): + def get_midi (self, f): + s = open (f).read () + s = re.sub ('LilyPond [0-9.]+', '', s) + return s + + def __init__ (self, f1, f2): + self.files = (f1, f2) + + s1 = self.get_midi (self.files[0]) + s2 = self.get_midi (self.files[1]) + + self.same = (s1 == s2) + + def name (self): + name = os.path.split (self.files[0])[1] + name = re.sub ('.midi', '', name) + return name + + def distance (self): + ## todo: could use import MIDI to pinpoint + ## what & where changed. + if self.same: + return 0 + else: + return 100; + def html_record_string (self, d1, d2): + return ''' + +%f + +%s +%s +''' % ((self.distance(),) + self.files) + +class SignatureFileLink (FileLink): def __init__ (self): self.original_name = '' self.base_names = ('','') self.system_links = {} self._distance = None - + def name (self): + return self.original_name + def add_system_link (self, link, number): self.system_links[number] = link @@ -295,10 +394,6 @@ class FileLink: return self._distance - def text_record_string (self): - return '%-30f %-20s\n' % (self.distance (), - self.original_name) - def source_file (self): for ext in ('.ly', '.ly.txt'): if os.path.exists (self.base_names[1] + ext): @@ -340,12 +435,51 @@ class FileLink: self.add_system_link (link, system_index[0]) + + def create_images (self, old_dir, new_dir, dest_dir): + + files_created = [[], []] + for oldnew in (0, 1): + pat = self.base_names[oldnew] + '.eps' + + for f in glob.glob (pat): + infile = f + outfile = (dest_dir + '/' + f).replace ('.eps', '.png') + + mkdir (os.path.split (outfile)[0]) + cmd = ('gs -sDEVICE=png16m -dGraphicsAlphaBits=4 -dTextAlphaBits=4 ' + ' -r101 ' + ' -sOutputFile=%(outfile)s -dNOSAFER -dEPSCrop -q -dNOPAUSE ' + ' %(infile)s -c quit ' % locals ()) + + files_created[oldnew].append (outfile) + system (cmd) + + return files_created + def link_files_for_html (self, old_dir, new_dir, dest_dir): - for ext in ('.png', '.ly'): + to_compare = [[], []] + + exts = ['.ly'] + if options.create_images: + to_compare = self.create_images (old_dir, new_dir, dest_dir) + else: + exts += ['.png', '-page*png'] + + for ext in exts: for oldnew in (0,1): - link_file (self.base_names[oldnew] + ext, - dest_dir + '/' + self.base_names[oldnew] + ext) + for f in glob.glob (self.base_names[oldnew] + ext): + dst = dest_dir + '/' + f + link_file (f, dst) + + if f.endswith ('.png'): + to_compare[oldnew].append (f) + + if options.compare_images: + for (old, new) in zip (to_compare[0], to_compare[1]): + compare_png_images (old, new, dest_dir) + def html_record_string (self, old_dir, new_dir): def img_cell (ly, img, name): if not name: @@ -362,14 +496,45 @@ class FileLink: ''' % locals () - + def multi_img_cell (ly, imgs, name): + if not name: + name = 'source' + else: + name = '%s' % name + + imgs_str = '\n'.join ([''' + +
''' % (img, img) + for img in imgs]) + + + return ''' + +%(imgs_str)s +(%(name)s) + + +''' % locals () + + + + def cell (base, name): + pat = base + '-page*.png' + pages = glob.glob (pat) + + if pages: + return multi_img_cell (base + '.ly', sorted (pages), name) + else: + return img_cell (base + '.ly', base + '.png', name) + - img_1 = self.base_names[0] + '.png' - ly_1 = self.base_names[0] + '.ly' - img_2 = self.base_names[1] + '.png' - ly_2 = self.base_names[1] + '.ly' html_2 = self.base_names[1] + '.html' name = self.original_name + + cell_1 = cell (self.base_names[0], name) + cell_2 = cell (self.base_names[1], name) + if options.compare_images: + cell_2 = cell_2.replace ('.png', '.compare.jpeg') html_entry = ''' @@ -381,9 +546,7 @@ class FileLink: %s %s -''' % (self.distance (), html_2, - img_cell (ly_1, img_1, name), img_cell (ly_2, img_2, name)) - +''' % (self.distance (), html_2, cell_1, cell_2) return html_entry @@ -498,23 +661,35 @@ class ComparisonData: self.compare_trees (d1, d2) def compare_directories (self, dir1, dir2): + for ext in ['signature', 'midi']: + (paired, m1, m2) = paired_files (dir1, dir2, '*.' + ext) - (paired, m1, m2) = paired_files (dir1, dir2, '*.signature') - - self.missing += [(dir1, m) for m in m1] - self.added += [(dir2, m) for m in m2] + self.missing += [(dir1, m) for m in m1] + self.added += [(dir2, m) for m in m2] - for p in paired: - if (inspect_max_count - and len (self.file_links) > inspect_max_count): + for p in paired: + if (options.max_count + and len (self.file_links) > options.max_count): + + continue - continue - - f2 = dir2 + '/' + p - f1 = dir1 + '/' + p - self.compare_files (f1, f2) + f2 = dir2 + '/' + p + f1 = dir1 + '/' + p + self.compare_files (f1, f2) def compare_files (self, f1, f2): + if f1.endswith ('signature'): + self.compare_signature_files (f1, f2) + elif f1.endswith ('midi'): + self.compare_midi_files (f1, f2) + + def compare_midi_files (self, f1, f2): + name = os.path.split (f1)[1] + + file_link = MidiFileLink (f1, f2) + self.file_links[name] = file_link + + def compare_signature_files (self, f1, f2): name = os.path.split (f1)[1] name = re.sub ('-[0-9]+.signature', '', name) @@ -522,17 +697,17 @@ class ComparisonData: try: file_link = self.file_links[name] except KeyError: - file_link = FileLink () + file_link = SignatureFileLink () self.file_links[name] = file_link - file_link.add_file_compare (f1,f2) + file_link.add_file_compare (f1, f2) def write_text_result_page (self, filename, threshold): - print 'writing "%s"' % filename out = None if filename == '': out = sys.stdout else: + print 'writing "%s"' % filename out = open_write_file (filename) ## todo: support more scores. @@ -569,17 +744,20 @@ class ComparisonData: if score <= threshold: continue - link.write_html_system_details (dir1, dir2, dest_dir) link.link_files_for_html (dir1, dir2, dest_dir) + link.write_html_system_details (dir1, dir2, dest_dir) + html += link.html_record_string (dir1, dir2) + short_dir1 = shorten_string (dir1) + short_dir2 = shorten_string (dir2) html = ''' - - + + %(html)s
distance%(dir1)s%(dir2)s%(short_dir1)s%(short_dir2)s
@@ -650,43 +828,59 @@ def test_paired_files (): def test_compare_trees (): system ('rm -rf dir1 dir2') system ('mkdir dir1 dir2') - system ('cp 20{-*.signature,.ly,.png} dir1') - system ('cp 20{-*.signature,.ly,.png} dir2') - system ('cp 20expr{-*.signature,.ly,.png} dir1') - system ('cp 19{-*.signature,.ly,.png} dir2/') - system ('cp 19{-*.signature,.ly,.png} dir1/') + system ('cp 20{-*.signature,.ly,.png,.eps} dir1') + system ('cp 20{-*.signature,.ly,.png,.eps} dir2') + system ('cp 20expr{-*.signature,.ly,.png,.eps} dir1') + system ('cp 19{-*.signature,.ly,.png,.eps} dir2/') + system ('cp 19{-*.signature,.ly,.png,.eps} dir1/') system ('cp 19-1.signature 19-sub-1.signature') system ('cp 19.ly 19-sub.ly') system ('cp 19.png 19-sub.png') + system ('cp 19.eps 19-sub.eps') + + system ('cp 20multipage* dir1') + system ('cp 20multipage* dir2') + system ('cp 19multipage-1.signature dir2/20multipage-1.signature') + system ('mkdir -p dir1/subdir/ dir2/subdir/') - system ('cp 19-sub{-*.signature,.ly,.png} dir1/subdir/') - system ('cp 19-sub{-*.signature,.ly,.png} dir2/subdir/') - system ('cp 20grob{-*.signature,.ly,.png} dir2/') - system ('cp 20grob{-*.signature,.ly,.png} dir1/') + system ('cp 19-sub{-*.signature,.ly,.png,.eps} dir1/subdir/') + system ('cp 19-sub{-*.signature,.ly,.png,.eps} dir2/subdir/') + system ('cp 20grob{-*.signature,.ly,.png,.eps} dir2/') + system ('cp 20grob{-*.signature,.ly,.png,.eps} dir1/') ## introduce differences system ('cp 19-1.signature dir2/20-1.signature') + system ('cp 19.png dir2/20.png') + system ('cp 19multipage-page1.png dir2/20multipage-page1.png') system ('cp 20-1.signature dir2/subdir/19-sub-1.signature') + system ('cp 20.png dir2/subdir/19-sub.png') ## radical diffs. system ('cp 19-1.signature dir2/20grob-1.signature') system ('cp 19-1.signature dir2/20grob-2.signature') + system ('cp 19multipage.midi dir1/midi-differ.midi') + system ('cp 20multipage.midi dir2/midi-differ.midi') compare_trees ('dir1', 'dir2', 'compare-dir1dir2', 0.5) def test_basic_compare (): - ly_template = r"""#(set! toplevel-score-handler print-score-with-defaults) -#(set! toplevel-music-handler - (lambda (p m) - (if (not (eq? (ly:music-property m 'void) #t)) - (print-score-with-defaults - p (scorify-music m p))))) + ly_template = r""" -\sourcefilename "my-source.ly" +\version "2.10.0" +#(set! toplevel-score-handler print-score-with-defaults) + #(set! toplevel-music-handler + (lambda (p m) + (if (not (eq? (ly:music-property m 'void) #t)) + (print-score-with-defaults + p (scorify-music m p))))) +\sourcefilename "my-source.ly" + %(papermod)s +\header { tagline = ##f } +\score { << \new Staff \relative c { c4^"%(userstring)s" %(extragrob)s @@ -695,6 +889,9 @@ def test_basic_compare (): c4^"%(userstring)s" %(extragrob)s } >> +\layout{} +} + """ dicts = [{ 'papermod' : '', @@ -712,8 +909,7 @@ def test_basic_compare (): { 'papermod' : '', 'name' : '20grob', 'extragrob': 'r2. \\break c1', - 'userstring': 'test' } - + 'userstring': 'test' }, ] for d in dicts: @@ -722,6 +918,21 @@ def test_basic_compare (): names = [d['name'] for d in dicts] system ('lilypond -ddump-signatures --png -b eps ' + ' '.join (names)) + + + multipage_str = r''' + #(set-default-paper-size "a6") + \score { + \relative {c1 \pageBreak c1 } + \layout {} + \midi {} + } + ''' + + open ('20multipage', 'w').write (multipage_str.replace ('c1', 'd1')) + open ('19multipage', 'w').write ('#(set-global-staff-size 19.5)\n' + multipage_str) + system ('lilypond -ddump-signatures --png 19multipage 20multipage ') + test_compare_signatures (names) def test_compare_signatures (names, timing=False): @@ -766,7 +977,7 @@ def test_compare_signatures (names, timing=False): def run_tests (): - dir = 'output-distance-test' + dir = 'test-output-distance' do_clean = not os.path.exists (dir) @@ -808,9 +1019,29 @@ def main (): type="float", help='threshold for geometric distance') - (o,a) = p.parse_args () + p.add_option ('--no-compare-images', + dest="compare_images", + default=True, + action="store_false", + help="Don't run graphical comparisons") + + p.add_option ('--create-images', + dest="create_images", + default=False, + action="store_true", + help="Create PNGs from EPSes") + + p.add_option ('-o', '--output-dir', + dest="output_dir", + default=None, + action="store", + type="string", + help='where to put the test results [tree2/compare-tree1tree2]') - if o.run_test: + global options + (options, a) = p.parse_args () + + if options.run_test: run_tests () sys.exit (0) @@ -818,11 +1049,12 @@ def main (): p.print_usage() sys.exit (2) - global inspect_max_count - inspect_max_count = o.max_count - - compare_trees (a[0], a[1], os.path.join (a[1], 'compare-' + a[0]), - o.threshold) + name = options.output_dir + if not name: + name = a[0].replace ('/', '') + name = os.path.join (a[1], 'compare-' + shorten_string (name)) + + compare_trees (a[0], a[1], name, options.threshold) if __name__ == '__main__': main()