X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=python%2Fbook_snippets.py;h=f128ac16fff8801f4c6f2774b37e160e543110d5;hb=ea4fdf1afa3e6bb9a7c586f5a533be93ff3312d3;hp=443ad3c363ed5e23fbf06b099a4d81d7cfa2018d;hpb=076a09a308e55d7e3504051d5f2edd3256aa8b96;p=lilypond.git diff --git a/python/book_snippets.py b/python/book_snippets.py index 443ad3c363..f128ac16ff 100644 --- a/python/book_snippets.py +++ b/python/book_snippets.py @@ -6,7 +6,11 @@ global _;_=ly._ import re import os import copy -from subprocess import Popen, PIPE +# TODO: We are using os.popen3, which has been deprecated since python 2.6. The +# suggested replacement is the Popen function of the subprocess module. +# Unfortunately, on windows this needs the msvcrt module, which doesn't seem +# to be available in GUB?!?!?! +# from subprocess import Popen, PIPE progress = ly.progress warning = ly.warning @@ -34,14 +38,11 @@ EXAMPLEINDENT = 'exampleindent' FILENAME = 'filename' FILTER = 'filter' FRAGMENT = 'fragment' -LANG = 'lang' ## TODO: This is handled nowhere! LAYOUT = 'layout' -LILYQUOTE = 'lilyquote' LINE_WIDTH = 'line-width' NOFRAGMENT = 'nofragment' NOGETTEXT = 'nogettext' NOINDENT = 'noindent' -NOQUOTE = 'noquote' INDENT = 'indent' NORAGGED_RIGHT = 'noragged-right' NOTES = 'body' @@ -49,6 +50,7 @@ NOTIME = 'notime' OUTPUT = 'output' OUTPUTIMAGE = 'outputimage' PAPER = 'paper' +PAPERSIZE = 'papersize' PREAMBLE = 'preamble' PRINTFILENAME = 'printfilename' QUOTE = 'quote' @@ -63,7 +65,6 @@ VERSION = 'lilypondversion' # NOTIME and NOGETTEXT have no opposite so they aren't part of this # dictionary. -# NOQUOTE is used internally only. no_options = { NOFRAGMENT: FRAGMENT, NOINDENT: INDENT, @@ -87,7 +88,6 @@ simple_options = [ PRINTFILENAME, DOCTITLE, TEXIDOC, - LANG, VERBATIM, FILENAME, ALT, @@ -108,10 +108,10 @@ snippet_options = { ## PAPER: { + PAPERSIZE: r'''#(set-paper-size "%(papersize)s")''', INDENT: r'''indent = %(indent)s''', LINE_WIDTH: r'''line-width = %(line-width)s''', QUOTE: r'''line-width = %(line-width)s - 2.0 * %(exampleindent)s''', - LILYQUOTE: r'''line-width = %(line-width)s - 2.0 * %(exampleindent)s''', RAGGED_RIGHT: r'''ragged-right = ##t''', NORAGGED_RIGHT: r'''ragged-right = ##f''', }, @@ -139,24 +139,9 @@ snippet_options = { -FRAGMENT_LY = r''' -%(notes_string)s -{ - - -%% **************************************************************** -%% ly snippet contents follows: -%% **************************************************************** -%(code)s - - -%% **************************************************************** -%% end ly snippet -%% **************************************************************** -} -''' - def classic_lilypond_book_compatibility (key, value): + if key == 'lilyquote': + return (QUOTE, value) if key == 'singleline' and value == None: return (RAGGED_RIGHT, None) @@ -177,6 +162,8 @@ def classic_lilypond_book_compatibility (key, value): return (None, None) +# TODO: Remove the 1mm additional padding in the line-width, once lilypond +# creates tighter cropped images! PREAMBLE_LY = '''%%%% Generated by %(program_name)s %%%% Options: [%(option_string)s] \\include "lilypond-book-preamble.ly" @@ -190,13 +177,16 @@ PREAMBLE_LY = '''%%%% Generated by %(program_name)s \paper { %(paper_string)s - force-assignment = #"" - line-width = #(- line-width (* mm %(padding_mm)f)) + %% offset the left padding, also add 1mm as lilypond creates cropped + %% images with a little space on the right + line-width = #(- line-width (* mm %(padding_mm)f) (* mm 1)) } \layout { %(layout_string)s } + +%(safe_mode_string)s ''' @@ -214,10 +204,23 @@ FULL_LY = ''' %% **************************************************************** ''' +FRAGMENT_LY = r''' +%(notes_string)s +{ +%% **************************************************************** +%% ly snippet contents follows: +%% **************************************************************** +%(code)s +%% **************************************************************** +%% end ly snippet +%% **************************************************************** +} +''' + @@ -392,13 +395,13 @@ class LilypondSnippet (Snippet): self.option_dict[option] = None - # If LINE_WIDTH is used without parameter, set it to default. + # Store if we have an explicit line-width given has_line_width = self.option_dict.has_key (LINE_WIDTH) if has_line_width and self.option_dict[LINE_WIDTH] == None: has_line_width = False del self.option_dict[LINE_WIDTH] - # TODO: Can't we do that more efficiently (built-in python func?) + # Use default options (i.e. auto-detected line-width, etc) for k in self.formatter.default_snippet_options: if k not in self.option_dict: self.option_dict[k] = self.formatter.default_snippet_options[k] @@ -409,22 +412,6 @@ class LilypondSnippet (Snippet): if has_relative and not self.option_dict.has_key (FRAGMENT): self.option_dict[FRAGMENT] = None - if not has_line_width: - if type == 'lilypond' or FRAGMENT in self.option_dict: - self.option_dict[RAGGED_RIGHT] = None - - if type == 'lilypond': - if LINE_WIDTH in self.option_dict: - del self.option_dict[LINE_WIDTH] - else: - if RAGGED_RIGHT in self.option_dict: - if LINE_WIDTH in self.option_dict: - del self.option_dict[LINE_WIDTH] - - if QUOTE in self.option_dict or type == 'lilypond': - if LINE_WIDTH in self.option_dict: - del self.option_dict[LINE_WIDTH] - if not INDENT in self.option_dict: self.option_dict[INDENT] = '0\\mm' @@ -435,8 +422,7 @@ class LilypondSnippet (Snippet): # all settings before writing them in the \paper block. if not LINE_WIDTH in self.option_dict: if not QUOTE in self.option_dict: - if not LILYQUOTE in self.option_dict: - self.option_dict[LINE_WIDTH] = "#(- paper-width \ + self.option_dict[LINE_WIDTH] = "#(- paper-width \ left-margin-default right-margin-default)" def get_option_list (self): @@ -452,10 +438,6 @@ left-margin-default right-margin-default)" return self.option_list def compose_ly (self, code): - if FRAGMENT in self.option_dict: - body = FRAGMENT_LY - else: - body = FULL_LY # Defaults. relative = 1 @@ -547,15 +529,29 @@ left-margin-default right-margin-default)" elif relative > 0: relative_quotes += "'" * relative + # put paper-size first, if it exists + for i,elem in enumerate(compose_dict[PAPER]): + if elem.startswith("#(set-paper-size"): + compose_dict[PAPER].insert(0, compose_dict[PAPER].pop(i)) + break + paper_string = '\n '.join (compose_dict[PAPER]) % override layout_string = '\n '.join (compose_dict[LAYOUT]) % override notes_string = '\n '.join (compose_dict[NOTES]) % vars () preamble_string = '\n '.join (compose_dict[PREAMBLE]) % override padding_mm = self.global_options.padding_mm + if self.global_options.safe_mode: + safe_mode_string = "#(ly:set-option 'safe #t)" + else: + safe_mode_string = "" d = globals().copy() d.update (locals()) d.update (self.global_options.information) + if FRAGMENT in self.option_dict: + body = FRAGMENT_LY + else: + body = FULL_LY return (PREAMBLE_LY + body) % d def get_checksum (self): @@ -584,7 +580,7 @@ left-margin-default right-margin-default)" def basename (self): cs = self.get_checksum () - name = '%s/lily-%s' % (cs[:2], cs[2:]) + name = os.path.join (cs[:2], 'lily-%s' % cs[2:]) return name final_basename = basename @@ -641,6 +637,11 @@ printing diff against existing file." % filename) os.makedirs (dst_path) os.link (src, dst) + def additional_files_to_consider (self, base, full): + return [] + def additional_files_required (self, base, full): + return [] + def all_output_files (self, output_dir, output_dir_files): """Return all files generated in lily_output_dir, a set. @@ -704,6 +705,8 @@ printing diff against existing file." % filename) if 'ddump-signature' in self.global_options.process_cmd: consider_file (systemfile + '.signature') + map (consider_file, self.additional_files_to_consider (base, full)) + map (require_file, self.additional_files_required (base, full)) return (result, missing) @@ -715,12 +718,12 @@ printing diff against existing file." % filename) """Pass input through cmd, and return the result.""" if self.global_options.verbose: - progress (_ ("Opening filter `%s'\n") % cmd) - - #(stdin, stdout, stderr) = os.popen3 (cmd) + progress (_ ("Running through filter `%s'\n") % cmd) - p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) - (stdin, stdout, stderr) = (p.stdin, p.stdout, p.stderr) + # TODO: Use Popen once we resolve the problem with msvcrt in Windows: + (stdin, stdout, stderr) = os.popen3 (cmd) + # p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) + # (stdin, stdout, stderr) = (p.stdin, p.stdout, p.stderr) stdin.write (input) status = stdin.close () @@ -728,16 +731,16 @@ printing diff against existing file." % filename) status = 0 output = stdout.read () status = stdout.close () - error = stderr.read () + err = stderr.read () if not status: status = 0 signal = 0x0f & status - if status or (not output and error): + if status or (not output and err): exit_status = status >> 8 ly.error (_ ("`%s' failed (%d)") % (cmd, exit_status)) ly.error (_ ("The error log is as follows:")) - ly.stderr_write (error) + ly.stderr_write (err) ly.stderr_write (stderr.read ()) exit (status) @@ -790,7 +793,9 @@ re_end_verbatim = re.compile (r'\s+%.*?end verbatim.*$', re.M) class LilypondFileSnippet (LilypondSnippet): def __init__ (self, type, match, formatter, line_number, global_options): LilypondSnippet.__init__ (self, type, match, formatter, line_number, global_options) - self.contents = file (BookBase.find_file (self.substring ('filename'), global_options.include_path)).read () + self.filename = self.substring ('filename') + self.ext = os.path.splitext (os.path.basename (self.filename))[1] + self.contents = file (BookBase.find_file (self.filename, global_options.include_path)).read () def get_snippet_code (self): return self.contents; @@ -806,18 +811,113 @@ class LilypondFileSnippet (LilypondSnippet): return s def ly (self): - name = self.substring ('filename') + name = self.filename return ('\\sourcefilename \"%s\"\n\\sourcefileline 0\n%s' % (name, self.contents)) def final_basename (self): if self.global_options.use_source_file_names: - base = os.path.splitext (os.path.basename (self.substring ('filename')))[0] + base = os.path.splitext (os.path.basename (self.filename))[0] return base else: return self.basename () +class MusicXMLFileSnippet (LilypondFileSnippet): + def __init__ (self, type, match, formatter, line_number, global_options): + LilypondFileSnippet.__init__ (self, type, match, formatter, line_number, global_options) + self.compressed = False + self.converted_ly = None + self.musicxml_options_dict = { + 'verbose': '--verbose', + 'lxml': '--lxml', + 'compressed': '--compressed', + 'relative': '--relative', + 'absolute': '--absolute', + 'no-articulation-directions': '--no-articulation-directions', + 'no-rest-positions': '--no-rest-positions', + 'no-page-layout': '--no-page-layout', + 'no-beaming': '--no-beaming', + 'language': '--language', + } + + def snippet_options (self): + return self.musicxml_options_dict.keys () + + def convert_from_musicxml (self): + name = self.filename + xml2ly_option_list = [] + for (key, value) in self.option_dict.items (): + cmd_key = self.musicxml_options_dict.get (key, None) + if cmd_key == None: + continue + if value == None: + xml2ly_option_list.append (cmd_key) + else: + xml2ly_option_list.append (cmd_key + '=' + value) + if ('.mxl' in name) and ('--compressed' not in xml2ly_option_list): + xml2ly_option_list.append ('--compressed') + self.compressed = True + opts = " ".join (xml2ly_option_list) + progress (_ ("Converting MusicXML file `%s'...\n") % self.filename) + + ly_code = self.filter_pipe (self.contents, 'musicxml2ly %s --out=- - ' % opts) + return ly_code + + def ly (self): + if self.converted_ly == None: + self.converted_ly = self.convert_from_musicxml () + name = self.filename + return ('\\sourcefilename \"%s\"\n\\sourcefileline 0\n%s' + % (name, self.converted_ly)) + + def additional_files_required (self, base, full): + result = []; + if self.compressed: + result.append (base + '.mxl') + else: + result.append (base + '.xml') + return result + + def write_ly (self): + base = self.basename () + path = os.path.join (self.global_options.lily_output_dir, base) + directory = os.path.split(path)[0] + if not os.path.isdir (directory): + os.makedirs (directory) + + # First write the XML to a file (so we can link it!) + if self.compressed: + xmlfilename = path + '.mxl' + else: + xmlfilename = path + '.xml' + if os.path.exists (xmlfilename): + diff_against_existing = self.filter_pipe (self.contents, 'diff -u %s - ' % xmlfilename) + if diff_against_existing: + warning (_ ("%s: duplicate filename but different contents of orginal file,\n\ +printing diff against existing file.") % xmlfilename) + ly.stderr_write (diff_against_existing) + else: + out = file (xmlfilename, 'w') + out.write (self.contents) + out.close () + + # also write the converted lilypond + filename = path + '.ly' + if os.path.exists (filename): + diff_against_existing = self.filter_pipe (self.full_ly (), 'diff -u %s -' % filename) + if diff_against_existing: + warning (_ ("%s: duplicate filename but different contents of converted lilypond file,\n\ +printing diff against existing file.") % filename) + ly.stderr_write (diff_against_existing) + else: + out = file (filename, 'w') + out.write (self.full_ly ()) + out.close () + file (path + '.txt', 'w').write ('image of music') + + + class LilyPondVersionString (Snippet): """A string that does not require extra memory.""" def __init__ (self, type, match, formatter, line_number, global_options): @@ -833,4 +933,5 @@ snippet_type_to_class = { 'lilypond': LilypondSnippet, 'include': IncludeSnippet, 'lilypondversion': LilyPondVersionString, + 'musicxml_file': MusicXMLFileSnippet, }