X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scripts%2Flilypond-book.py;h=64a90310b715c317b19f57e42b1339e0e7f2c5d8;hb=edf9d00fea686457b4469b82a435d5dc3bf09a56;hp=dc035b4b5cffa835906a0bea4e0bc9734e048276;hpb=794dcbdb52faf4292036cd1b0270a956cf4316a3;p=lilypond.git diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py index dc035b4b5c..64a90310b7 100644 --- a/scripts/lilypond-book.py +++ b/scripts/lilypond-book.py @@ -1,5 +1,20 @@ #!@TARGET_PYTHON@ +# This file is part of LilyPond, the GNU music typesetter. +# +# LilyPond is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# LilyPond is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with LilyPond. If not, see . + ''' Example usage: @@ -111,7 +126,7 @@ def warranty (): %s %s -''' % ( _ ('Copyright (c) %s by') % '2001--2009', +''' % ( _ ('Copyright (c) %s by') % '2001--2010', '\n '.join (authors), _ ("Distributed under terms of the GNU General Public License."), _ ("It comes with NO WARRANTY."))) @@ -149,7 +164,8 @@ def get_option_parser (): default='') p.add_option ('--latex-program', - help=_ ("run executable PROG instead of latex"), + help=_ ("run executable PROG instead of latex, or in\n\ +case --pdf option is set instead of pdflatex"), metavar=_ ("PROG"), action='store', dest='latex_program', default='latex') @@ -161,11 +177,28 @@ def get_option_parser (): type="float", default=3.0) + p.add_option ('--lily-output-dir', + help=_ ("write lily-XXX files to DIR, link into --output dir"), + metavar=_ ("DIR"), + action='store', dest='lily_output_dir', + default=None) + p.add_option ("-o", '--output', help=_ ("write output to DIR"), metavar=_ ("DIR"), action='store', dest='output_dir', default='') + p.add_option ('--pdf', + action="store_true", + dest="create_pdf", + help=_ ("create PDF files for use with PDFTeX"), + default=False) + + p.add_option ('-P', '--process', metavar=_ ("COMMAND"), + help = _ ("process ly_files using COMMAND FILE..."), + action='store', + dest='process_cmd', default='') + p.add_option ('--skip-lily-check', help=_ ("do not fail if no lilypond output is found"), metavar=_ ("DIR"), @@ -178,21 +211,9 @@ def get_option_parser (): action='store_true', dest='skip_png_check', default=False) - p.add_option ('--lily-output-dir', - help=_ ("write lily-XXX files to DIR, link into --output dir"), - metavar=_ ("DIR"), - action='store', dest='lily_output_dir', - default=None) - - p.add_option ('-P', '--process', metavar=_ ("COMMAND"), - help = _ ("process ly_files using COMMAND FILE..."), - action='store', - dest='process_cmd', default='') - - p.add_option ('--pdf', - action="store_true", - dest="create_pdf", - help=_ ("create PDF files for use with PDFTeX"), + p.add_option ('--use-source-file-names', + help=_ ("write snippet output files with the same base name as their source file"), + action='store_true', dest='use_source_file_names', default=False) p.add_option ('-V', '--verbose', help=_ ("be verbose"), @@ -276,13 +297,19 @@ FILENAME = 'filename' ALT = 'alt' -# NOTIME has no opposite so it isn't part of this dictionary. +# 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, } +# Options that have no impact on processing by lilypond (or --process +# argument) +PROCESSING_INDEPENDENT_OPTIONS = ( + ALT, NOGETTEXT, VERBATIM, ADDVERSION, + TEXIDOC, DOCTITLE, VERSION, PRINTFILENAME) # Recognize special sequences in the input. # @@ -363,9 +390,9 @@ snippet_res = { r'''(?mx) (?P .*?)\s*:)?\s* + (\s+(?P.*?))?\s*:\s* (?P.*?) - />)''', + \s*/>)''', 'lilypond_block': r'''(?msx) @@ -374,7 +401,7 @@ snippet_res = { \s*(?P.*?)\s* > (?P.*?) - )''', + )''', 'lilypond_file': r'''(?mx) @@ -383,7 +410,7 @@ snippet_res = { \s*(?P.*?)\s* > \s*(?P.*?)\s* - )''', + )''', 'multiline_comment': r'''(?smx) @@ -1116,13 +1143,28 @@ class LilypondSnippet (Snippet): if not INDENT in self.option_dict: self.option_dict[INDENT] = '0\\mm' - # The QUOTE pattern from ly_options only emits the `line-width' - # keyword. - if has_line_width and QUOTE in self.option_dict: - if no_line_width_value: - del self.option_dict[LINE_WIDTH] - else: - del self.option_dict[QUOTE] + # Set a default line-width if there is none. We need this, because + # lilypond-book has set left-padding by default and therefore does + # #(define line-width (- line-width (* 3 mm))) + # TODO: Junk this ugly hack if the code gets rewritten to concatenate + # 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 \ +left-margin-default right-margin-default)" + + def get_option_list (self): + if not 'option_list' in self.__dict__: + option_list = [] + for (key, value) in self.option_dict.items (): + if value == None: + option_list.append (key) + else: + option_list.append (key + '=' + value) + option_list.sort () + self.option_list = option_list + return self.option_list def compose_ly (self, code): if FRAGMENT in self.option_dict: @@ -1161,19 +1203,22 @@ class LilypondSnippet (Snippet): override.update (default_ly_options) option_list = [] - for (key, value) in self.option_dict.items (): - if value == None: - option_list.append (key) + for option in self.get_option_list (): + for name in PROCESSING_INDEPENDENT_OPTIONS: + if option.startswith (name): + break else: - option_list.append (key + '=' + value) + option_list.append (option) option_string = ','.join (option_list) - compose_dict = {} compose_types = [NOTES, PREAMBLE, LAYOUT, PAPER] for a in compose_types: compose_dict[a] = [] - for (key, value) in self.option_dict.items (): + option_names = self.option_dict.keys () + option_names.sort () + for key in option_names: + value = self.option_dict[key] (c_key, c_value) = classic_lilypond_book_compatibility (key, value) if c_key: if c_value: @@ -1235,7 +1280,16 @@ class LilypondSnippet (Snippet): except ImportError: from md5 import md5 - hash = md5 (self.relevant_contents (self.full_ly ())) + # We only want to calculate the hash based on the snippet + # code plus fragment options relevant to processing by + # lilypond, not the snippet + preamble + hash = md5 (self.relevant_contents (self.ly ())) + for option in self.get_option_list (): + for name in PROCESSING_INDEPENDENT_OPTIONS: + if option.startswith (name): + break + else: + hash.update (option) ## let's not create too long names. self.checksum = hash.hexdigest ()[:10] @@ -1244,22 +1298,31 @@ class LilypondSnippet (Snippet): def basename (self): cs = self.get_checksum () - name = '%s/lily-%s' % (cs[:2], cs[2:10]) + name = '%s/lily-%s' % (cs[:2], cs[2:]) return name + final_basename = basename + def write_ly (self): base = self.basename () path = os.path.join (global_options.lily_output_dir, base) directory = os.path.split(path)[0] if not os.path.isdir (directory): os.makedirs (directory) - out = file (path + '.ly', 'w') - out.write (self.full_ly ()) - file (path + '.txt', 'w').write ('image of music') + filename = path + '.ly' + if os.path.exists (filename): + diff_against_existing = filter_pipe (self.full_ly (), 'diff -u %s -' % filename) + if diff_against_existing: + warning ("%s: duplicate filename but different contents of orginal file,\n\ +printing diff against existing file." % filename) + ly.stderr_write (diff_against_existing) + else: + out = file (filename, 'w') + out.write (self.full_ly ()) + file (path + '.txt', 'w').write ('image of music') def relevant_contents (self, ly): - return re.sub (r'\\(version|sourcefileline|sourcefilename)[^\n]*\n|' + - NOGETTEXT + '[,\]]', '', ly) + return re.sub (r'\\(version|sourcefileline|sourcefilename)[^\n]*\n', '', ly) def link_all_output_files (self, output_dir, output_dir_files, destination): existing, missing = self.all_output_files (output_dir, output_dir_files) @@ -1267,13 +1330,25 @@ class LilypondSnippet (Snippet): print '\nMissing', missing raise CompileError(self.basename()) for name in existing: + if (global_options.use_source_file_names + and isinstance (self, LilypondFileSnippet)): + base, ext = os.path.splitext (name) + components = base.split ('-') + # ugh, assume filenames with prefix with one dash (lily-xxxx) + if len (components) > 2: + base_suffix = '-' + components[-1] + else: + base_suffix = '' + final_name = self.final_basename () + base_suffix + ext + else: + final_name = name try: - os.unlink (os.path.join (destination, name)) + os.unlink (os.path.join (destination, final_name)) except OSError: pass src = os.path.join (output_dir, name) - dst = os.path.join (destination, name) + dst = os.path.join (destination, final_name) dst_path = os.path.split(dst)[0] if not os.path.isdir (dst_path): os.makedirs (dst_path) @@ -1374,7 +1449,7 @@ class LilypondSnippet (Snippet): return func (self) def get_images (self): - base = self.basename () + base = self.final_basename () single = '%(base)s.png' % vars () multiple = '%(base)s-page1.png' % vars () @@ -1391,7 +1466,7 @@ class LilypondSnippet (Snippet): def output_docbook (self): str = '' - base = self.basename () + base = self.final_basename () for image in self.get_images (): (base, ext) = os.path.splitext (image) str += output[DOCBOOK][OUTPUT] % vars () @@ -1407,7 +1482,7 @@ class LilypondSnippet (Snippet): def output_html (self): str = '' - base = self.basename () + base = self.final_basename () if self.format == HTML: str += self.output_print_filename (HTML) if VERBATIM in self.option_dict: @@ -1436,13 +1511,13 @@ class LilypondSnippet (Snippet): info_image_path = os.path.join (global_options.info_images_dir, base) str += output[TEXINFO][OUTPUTIMAGE] % vars () - base = self.basename () + base = self.final_basename () str += output[self.format][OUTPUT] % vars () return str def output_latex (self): str = '' - base = self.basename () + base = self.final_basename () if self.format == LATEX: str += self.output_print_filename (LATEX) if VERBATIM in self.option_dict: @@ -1463,7 +1538,7 @@ class LilypondSnippet (Snippet): def output_print_filename (self, format): str = '' if PRINTFILENAME in self.option_dict: - base = self.basename () + base = self.final_basename () filename = os.path.basename (self.substring ('filename')) str = output[format][PRINTFILENAME] % vars () @@ -1471,7 +1546,7 @@ class LilypondSnippet (Snippet): def output_texinfo (self): str = self.output_print_filename (TEXINFO) - base = self.basename () + base = self.final_basename () if DOCTITLE in self.option_dict: doctitle = base + '.doctitle' translated_doctitle = doctitle + document_language @@ -1534,6 +1609,13 @@ class LilypondFileSnippet (LilypondSnippet): return ('\\sourcefilename \"%s\"\n\\sourcefileline 0\n%s' % (name, self.contents)) + def final_basename (self): + if global_options.use_source_file_names: + base = os.path.splitext (os.path.basename (self.substring ('filename')))[0] + return base + else: + return self.basename () + class LilyPondVersionString (Snippet): """A string that does not require extra memory.""" @@ -1702,7 +1784,7 @@ def process_snippets (cmd, snippets, checksum = snippet_list_checksum (snippets) contents = '\n'.join (['snippet-map-%d.ly' % checksum] - + [snip.basename() + '.ly' for snip in snippets]) + + list (set ([snip.basename() + '.ly' for snip in snippets]))) name = os.path.join (lily_output_dir, 'snippet-names-%d.ly' % checksum) file (name, 'wb').write (contents) @@ -1751,17 +1833,17 @@ def get_latex_textwidth (source): os.unlink (logfile) columns = 0 - m = re.search ('columns=([0-9.]*)', parameter_string) + m = re.search ('columns=([0-9.]+)', parameter_string) if m: columns = int (m.group (1)) columnsep = 0 - m = re.search ('columnsep=([0-9.]*)pt', parameter_string) + m = re.search ('columnsep=([0-9.]+)pt', parameter_string) if m: columnsep = float (m.group (1)) textwidth = 0 - m = re.search ('textwidth=([0-9.]*)pt', parameter_string) + m = re.search ('textwidth=([0-9.]+)pt', parameter_string) if m: textwidth = float (m.group (1)) if columns: @@ -2072,6 +2154,8 @@ def main (): global_options.process_cmd += ' --formats=eps ' if global_options.create_pdf: global_options.process_cmd += "--pdf -dinclude-eps-fonts -dgs-load-fonts " + if global_options.latex_program == 'latex': + global_options.latex_program = 'pdflatex' if global_options.verbose: global_options.process_cmd += " --verbose "