X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scripts%2Flilypond-book.py;h=bdb0637d17ee418424e1d1e83eb5fc91f96315e7;hb=ece2e45d587f63565e81af44e1937ebe1f5e47a8;hp=c81e103177ec269c8ea7c60bf13a415fe634ab17;hpb=51ef5c4887f63a4b64863699626678164f86d26d;p=lilypond.git diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py index c81e103177..bdb0637d17 100644 --- a/scripts/lilypond-book.py +++ b/scripts/lilypond-book.py @@ -35,22 +35,11 @@ import commands import os import sys import re +import md5 -################ -# RELOCATION -################ - - -for d in ['@lilypond_datadir@', - '@lilypond_libdir@']: - sys.path.insert (0, os.path.join (d, 'python')) - -# dynamic relocation, for GUB binaries. -bindir = os.path.abspath (os.path.split (sys.argv[0])[0]) -for p in ['share', 'lib']: - datadir = os.path.abspath (bindir + '/../%s/lilypond/current/python/' % p) - sys.path.insert (0, datadir) - +""" +@relocate-preamble@ +""" import lilylib as ly import fontextract @@ -64,20 +53,19 @@ program_name = os.path.basename (sys.argv[0]) original_dir = os.getcwd () backend = 'ps' -help_summary = _ ( -'''Process LilyPond snippets in hybrid HTML, LaTeX, or texinfo document. - -Example usage: - - lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK - lilypond-book --filter="convert-ly --no-version --from=2.0.0 -" BOOK - lilypond-book --process='lilypond -I include' BOOK -''') +help_summary = ( +_ ("Process LilyPond snippets in hybrid HTML, LaTeX, texinfo or DocBook document.") ++ '\n\n' ++ _ ("Examples:") ++ ''' + lilypond-book --filter="tr '[a-z]' '[A-Z]'" %(BOOK)s + lilypond-book --filter="convert-ly --no-version --from=2.0.0 -" %(BOOK)s + lilypond-book --process='lilypond -I include' %(BOOK)s +''' % {'BOOK': _ ("BOOK")}) authors = ('Jan Nieuwenhuizen ', - 'Han-Wen Nienhuys ') + 'Han-Wen Nienhuys ') - ################################################################ def exit (i): if global_options.verbose: @@ -86,16 +74,15 @@ def exit (i): sys.exit (i) def identify (): - sys.stdout.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version)) + ly.encoded_write (sys.stdout, '%s (GNU LilyPond) %s\n' % (program_name, program_version)) -def progress (s): - sys.stderr.write (s) +progress = ly.progress def warning (s): - sys.stderr.write (program_name + ": " + _ ("warning: %s") % s + '\n') + ly.stderr_write (program_name + ": " + _ ("warning: %s") % s + '\n') def error (s): - sys.stderr.write (program_name + ": " + _ ("error: %s") % s + '\n') + ly.stderr_write (program_name + ": " + _ ("error: %s") % s + '\n') def ps_page_count (ps_name): header = open (ps_name).read (1024) @@ -106,21 +93,20 @@ def ps_page_count (ps_name): def warranty (): identify () - sys.stdout.write (''' + ly.encoded_write (sys.stdout, ''' %s %s %s %s -''' % ( _('Copyright (c) %s by') % '2001--2006', +''' % ( _ ('Copyright (c) %s by') % '2001--2007', ' '.join (authors), - _('Distributed under terms of the GNU General Public License.'), - _('It comes with NO WARRANTY.'))) - + _ ("Distributed under terms of the GNU General Public License."), + _ ("It comes with NO WARRANTY."))) def get_option_parser (): - p = ly.get_option_parser (usage='lilypond-book [OPTIONS] FILE', + p = ly.get_option_parser (usage=_ ("%s [OPTION]... FILE") % 'lilypond-book', version="@TOPLEVEL_VERSION@", description=help_summary) @@ -130,46 +116,56 @@ def get_option_parser (): help=_ ("pipe snippets through FILTER [convert-ly -n -]"), default=None) p.add_option ('-f', '--format', - help=_('''use output format FORMAT (texi [default], texi-html, latex, html)'''), + help=_ ("use output format FORMAT (texi [default], texi-html, latex, html, docbook)"), action='store') - p.add_option ("-I", '--include', help=_('add DIR to include path'), - metavar="DIR", + + p.add_option ("-I", '--include', help=_ ("add DIR to include path"), + metavar=_ ("DIR"), action='append', dest='include_path', default=[os.path.abspath (os.getcwd ())]) + + p.add_option ('--info-images-dir', help=_ ("format Texinfo output so that Info will " + "look for images of music in DIR"), + metavar=_ ("DIR"), + action='store', dest='info_images_dir', + default='') + + p.add_option ('--left-padding', + metavar=_ ("PAD"), + dest="padding_mm", + help=_ ("pad left side of music to align music inspite of uneven bar numbers (in mm)"), + type="float", + default=3.0) - p.add_option ("-o", '--output', help=_('write output to DIR'), - metavar="DIR", + p.add_option ("-o", '--output', help=_ ("write output to DIR"), + metavar=_ ("DIR"), action='store', dest='output_name', default='') - p.add_option ('-P', '--process', metavar=_("COMMAND"), + + p.add_option ('-P', '--process', metavar=_ ("COMMAND"), help = _ ("process ly_files using COMMAND FILE..."), action='store', - dest='process_cmd', default='lilypond -b eps') - + dest='process_cmd', default='lilypond -dbackend=eps') p.add_option ('--pdf', action="store_true", dest="create_pdf", - help="Create PDF files for use with PDFTeX", + help=_ ("create PDF files for use with PDFTeX"), default=False) - p.add_option ('', '--psfonts', action="store_true", dest="psfonts", - help=_ ('''extract all PostScript fonts into INPUT.psfonts for LaTeX''' - '''must use this with dvips -h INPUT.psfonts'''), + help=_ ('''extract all PostScript fonts into INPUT.psfonts for LaTeX +must use this with dvips -h INPUT.psfonts'''), default=None) - p.add_option ('-V', '--verbose', help=_("be verbose"), + p.add_option ('-V', '--verbose', help=_ ("be verbose"), action="store_true", default=False, dest="verbose") - p.add_option ('-w', '--warranty', - help=_("show warranty and copyright"), + help=_ ("show warranty and copyright"), action='store_true') - - - p.add_option_group ('bugs', - description='''Report bugs via http://post.gmane.org/post.php''' - '''?group=gmane.comp.gnu.lilypond.bugs\n''') - + p.add_option_group (_ ('Bugs'), + description=(_ ("Report bugs via") + + ''' http://post.gmane.org/post.php''' + '''?group=gmane.comp.gnu.lilypond.bugs\n''')) return p lilypond_binary = os.path.join ('@bindir@', 'lilypond') @@ -188,6 +184,7 @@ default_ly_options = { 'alt': "[image of music]" } # AFTER = 'after' BEFORE = 'before' +DOCBOOK = 'docbook' EXAMPLEINDENT = 'exampleindent' FILTER = 'filter' FRAGMENT = 'fragment' @@ -196,6 +193,7 @@ INDENT = 'indent' LATEX = 'latex' LAYOUT = 'layout' LINE_WIDTH = 'line-width' +LILYQUOTE = 'lilyquote' NOFRAGMENT = 'nofragment' NOINDENT = 'noindent' NOQUOTE = 'noquote' @@ -236,6 +234,43 @@ no_options = { # (?x) -- Ignore whitespace in patterns. no_match = 'a\ba' snippet_res = { + ## + DOCBOOK: { + 'include': + no_match, + + 'lilypond': + r'''(?smx) + (?P + <(?P(inline)?)mediaobject>\s*\s*.*?)")?>(?P.*?)\s*\s*)''', + + 'lilypond_block': + r'''(?smx) + (?P + <(?P(inline)?)mediaobject>\s*\s*.*?)")?>(?P.*?)\s*\s*)''', + + 'lilypond_file': + r'''(?smx) + (?P + <(?P(inline)?)mediaobject>\s*\s*.*?\.ly)"\s*(role="(?P.*?)")?\s*(/>|>\s*)\s*\s*)''', + + 'multiline_comment': + r'''(?smx) + (?P + \s*(?!@c\s+) + (?P) + \s)''', + + 'singleline_comment': + no_match, + + 'verb': + no_match, + + 'verbatim': + no_match, + + }, ## HTML: { 'include': @@ -433,6 +468,10 @@ snippet_res = { format_res = { + DOCBOOK: { + 'intertext': r',?\s*intertext=\".*?\"', + 'option_sep': '\s*', + }, HTML: { 'intertext': r',?\s*intertext=\".*?\"', 'option_sep': '\s*', @@ -477,6 +516,8 @@ ly_options = { 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''', PACKED: r'''packed = ##t''', @@ -502,6 +543,21 @@ ly_options = { } output = { + ## + DOCBOOK: { + FILTER: r'''%(code)s''', + + OUTPUT: r''' + + + + + ''', + + VERBATIM: r'''%(verb)s''', + + PRINTFILENAME: '%(filename)s' + }, ## HTML: { FILTER: r''' @@ -535,7 +591,6 @@ output = { LATEX: { OUTPUT: r'''{%% \parindent 0pt%% -\catcode`\@=12%% \ifx\preLilyPondExample \undefined%% \relax%% \else%% @@ -578,7 +633,7 @@ output = { OUTPUTIMAGE: r'''@noindent @ifinfo -@image{%(base)s,,,%(alt)s,%(ext)s} +@image{%(info_image_path)s,,,%(alt)s,%(ext)s} @end ifinfo @html

@@ -629,21 +684,20 @@ if 0: PREAMBLE_LY = '''%%%% Generated by %(program_name)s %%%% Options: [%(option_string)s] \\include "lilypond-book-preamble.ly" -%(preamble_string)s - - - - %% **************************************************************** %% Start cut-&-pastable-section %% **************************************************************** +%(preamble_string)s + \paper { #(define dump-extents #t) %(font_dump_setting)s %(paper_string)s + force-assignment = #"" + line-width = #(- line-width (* mm %(padding_mm)f)) } \layout { @@ -826,6 +880,9 @@ class Lilypond_snippet (Snippet): os = match.group ('options') self.do_options (os, self.type) + def verb_ly (self): + return self.substring ('code') + def ly (self): contents = self.substring ('code') return ('\\sourcefileline %d\n%s' @@ -843,7 +900,7 @@ class Lilypond_snippet (Snippet): options = split_options (option_string) for i in options: - if string.find (i, '=') > 0: + if '=' in i: (key, value) = re.split ('\s*=\s*', i) self.option_dict[key] = value else: @@ -998,7 +1055,7 @@ class Lilypond_snippet (Snippet): '\n ') % vars () preamble_string = string.join (compose_dict[PREAMBLE], '\n ') % override - + padding_mm = global_options.padding_mm font_dump_setting = '' if FONTLOAD in self.option_dict: font_dump_setting = '#(define-public force-eps-font-include #t)\n' @@ -1007,46 +1064,51 @@ class Lilypond_snippet (Snippet): d.update (locals()) return (PREAMBLE_LY + body) % d - # TODO: Use md5? def get_hash (self): if not self.hash: - self.hash = abs (hash (self.full_ly ())) + hash = md5.md5 (self.relevant_contents (self.full_ly ())) + + ## let's not create too long names. + self.hash = hash.hexdigest ()[:10] + return self.hash def basename (self): if FILENAME in self.option_dict: return self.option_dict[FILENAME] if global_options.use_hash: - return 'lily-%d' % self.get_hash () + return 'lily-%s' % self.get_hash () raise 'to be done' def write_ly (self): outf = open (self.basename () + '.ly', 'w') outf.write (self.full_ly ()) - open (self.basename () + '.txt', 'w').write ('image of music') + def relevant_contents (self, ly): + return re.sub (r'\\(version|sourcefileline|sourcefilename)[^\n]*\n', '', ly) + def ly_is_outdated (self): base = self.basename () - - tex_file = '%s.tex' % base - eps_file = '%s.eps' % base - system_file = '%s-systems.tex' % base - ly_file = '%s.ly' % base - ok = os.path.exists (ly_file) \ - and os.path.exists (system_file)\ - and os.stat (system_file)[stat.ST_SIZE] \ - and re.match ('% eof', open (system_file).readlines ()[-1]) - if ok and (not global_options.use_hash or FILENAME in self.option_dict): - ok = (self.full_ly () == open (ly_file).read ()) - if ok: - # TODO: Do something smart with target formats - # (ps, png) and m/ctimes. + ly_file = base + '.ly' + tex_file = base + '.tex' + eps_file = base + '.eps' + systems_file = base + '-systems.tex' + + if (os.path.exists (ly_file) + and os.path.exists (systems_file) + and os.stat (systems_file)[stat.ST_SIZE] + and re.match ('% eof', open (systems_file).readlines ()[-1]) + and (global_options.use_hash or FILENAME in self.option_dict) + and (self.relevant_contents (self.full_ly ()) + == self.relevant_contents (open (ly_file).read ()))): return None + return self def png_is_outdated (self): base = self.basename () + # FIXME: refactor stupid OK stuff ok = not self.ly_is_outdated () if global_options.format in (HTML, TEXINFO): ok = ok and os.path.exists (base + '.eps') @@ -1068,6 +1130,7 @@ class Lilypond_snippet (Snippet): if backend == 'ps': return 0 + # FIXME: refactor stupid OK stuff base = self.basename () ok = self.ly_is_outdated () ok = ok and (os.path.exists (base + '.texstr')) @@ -1102,13 +1165,29 @@ class Lilypond_snippet (Snippet): images = tuple (images) return images + def output_docbook (self): + str = '' + base = self.basename () + for image in self.get_images (): + (base, ext) = os.path.splitext (image) + str += output[DOCBOOK][OUTPUT] % vars () + str += self.output_print_filename (DOCBOOK) + if (self.substring('inline') == 'inline'): + str = '' + str + '' + else: + str = '' + str + '' + if VERBATIM in self.option_dict: + verb = verbatim_html (self.verb_ly ()) + str = output[DOCBOOK][VERBATIM] % vars () + str + return str + def output_html (self): str = '' base = self.basename () if global_options.format == HTML: str += self.output_print_filename (HTML) if VERBATIM in self.option_dict: - verb = verbatim_html (self.substring ('code')) + verb = verbatim_html (self.verb_ly ()) str += output[HTML][VERBATIM] % vars () if QUOTE in self.option_dict: str = output[HTML][QUOTE] % vars () @@ -1130,6 +1209,7 @@ class Lilypond_snippet (Snippet): # Specifying no extension is most robust. ext = '' alt = self.option_dict[ALT] + info_image_path = os.path.join (global_options.info_images_dir, base) str += output[TEXINFO][OUTPUTIMAGE] % vars () base = self.basename () @@ -1142,7 +1222,7 @@ class Lilypond_snippet (Snippet): if global_options.format == LATEX: str += self.output_print_filename (LATEX) if VERBATIM in self.option_dict: - verb = self.substring ('code') + verb = self.verb_ly () str += (output[LATEX][VERBATIM] % vars ()) str += (output[LATEX][OUTPUT] % vars ()) @@ -1180,13 +1260,16 @@ class Lilypond_snippet (Snippet): if os.path.exists (texidoc): str += '@include %(texidoc)s\n\n' % vars () + substr = '' if VERBATIM in self.option_dict: - verb = self.substring ('code') - str += (output[TEXINFO][VERBATIM] % vars ()) + verb = self.verb_ly () + substr += output[TEXINFO][VERBATIM] % vars () if not QUOTE in self.option_dict: - str = output[TEXINFO][NOQUOTE] % vars () - - str += self.output_info () + substr = output[TEXINFO][NOQUOTE] % {'str':substr} + substr += self.output_info () + if LILYQUOTE in self.option_dict: + substr = output[TEXINFO][QUOTE] % {'str':substr} + str += substr # str += ('@ifinfo\n' + self.output_info () + '\n@end ifinfo\n') # str += ('@tex\n' + self.output_latex () + '\n@end tex\n') @@ -1200,17 +1283,25 @@ class Lilypond_snippet (Snippet): return str +re_begin_verbatim = re.compile (r'\s+%.*?begin verbatim.*\n*', re.M) +re_end_verbatim = re.compile (r'\s+%.*?end verbatim.*$', re.M) + class Lilypond_file_snippet (Lilypond_snippet): - def ly (self): - name = self.substring ('filename') - contents = open (find_file (name)).read () + def __init__ (self, type, match, format, line_number): + Lilypond_snippet.__init__ (self, type, match, format, line_number) + self.contents = open (find_file (self.substring ('filename'))).read () - ## strip version string to make automated regtest comparisons - ## across versions easier. - contents = re.sub (r'\\version *"[^"]*"', '', contents) + def verb_ly (self): + s = self.contents + s = re_begin_verbatim.split (s)[-1] + s = re_end_verbatim.split (s)[0] + return s + def ly (self): + name = self.substring ('filename') return ('\\sourcefilename \"%s\"\n\\sourcefileline 0\n%s' - % (name, contents)) + % (name, self.contents)) + snippet_type_to_class = { 'lilypond_file': Lilypond_file_snippet, @@ -1332,8 +1423,8 @@ def filter_pipe (input, cmd): exit_status = status >> 8 error (_ ("`%s' failed (%d)") % (cmd, exit_status)) error (_ ("The error log is as follows:")) - sys.stderr.write (error) - sys.stderr.write (stderr.read ()) + ly.stderr_write (error) + ly.stderr_write (stderr.read ()) exit (status) if global_options.verbose: @@ -1364,12 +1455,15 @@ def process_snippets (cmd, ly_snippets, texstr_snippets, png_snippets): status = 0 def my_system (cmd): status = ly.system (cmd, - be_verbose=global_options.verbose, - progress_p=1) + be_verbose=global_options.verbose, + progress_p=1) - if global_options.format in (HTML, TEXINFO): + if global_options.format in (HTML, TEXINFO) and '--formats' not in cmd: cmd += ' --formats=png ' + elif global_options.format in (DOCBOOK) and '--formats' not in cmd: + cmd += ' --formats=png,pdf ' + # UGH # the --process=CMD switch is a bad idea # it is too generic for lilypond-book. @@ -1380,7 +1474,11 @@ def process_snippets (cmd, ly_snippets, texstr_snippets, png_snippets): my_system ('latex %s.texstr' % l) if ly_names: - my_system (string.join ([cmd, 'snippet-map.ly'] + ly_names)) + open ('snippet-names', 'wb').write ('\n'.join (['snippet-map.ly'] + + ly_names)) + + my_system (string.join ([cmd, 'snippet-names'])) + LATEX_INSPECTION_DOCUMENT = r''' \nonstopmode @@ -1396,7 +1494,7 @@ LATEX_INSPECTION_DOCUMENT = r''' def get_latex_textwidth (source): m = re.search (r'''(?P\\begin\s*{document})''', source) if m == None: - warning (_ ("Can't find \\begin{document} in LaTeX document")) + warning (_ ("cannot find \\begin{document} in LaTeX document")) ## what's a sensible default? return 550.0 @@ -1459,6 +1557,7 @@ ext2format = { '.texi': TEXINFO, '.texinfo': TEXINFO, '.xml': HTML, + '.lyxml': DOCBOOK } format2ext = { @@ -1466,6 +1565,7 @@ format2ext = { # TEXINFO: '.texinfo', TEXINFO: '.texi', LATEX: '.tex', + DOCBOOK: '.xml' } class Compile_error: @@ -1475,6 +1575,7 @@ def write_file_map (lys, name): snippet_map = open ('snippet-map.ly', 'w') snippet_map.write (""" #(define version-seen #t) +#(define output-empty-score-list #f) #(ly:add-file-name-alist '( """) for ly in lys: @@ -1487,7 +1588,7 @@ def write_file_map (lys, name): def do_process_cmd (chunks, input_name): all_lys = filter (lambda x: is_derived_class (x.__class__, Lilypond_snippet), - chunks) + chunks) write_file_map (all_lys, input_name) ly_outdated = filter (lambda x: is_derived_class (x.__class__, @@ -1523,7 +1624,7 @@ def guess_format (input_filename): # FIXME format = ext2format[e] else: - error (_ ("can't determine format for: %s" \ + error (_ ("cannot determine format for: %s" \ % input_filename)) exit (1) return format @@ -1683,7 +1784,24 @@ def do_options (): return args +def psfonts_warning (options, basename): + if options.format in (TEXINFO, LATEX): + psfonts_file = os.path.join (options.output_name, basename + '.psfonts') + output = os.path.join (options.output_name, basename + '.dvi' ) + + if not options.create_pdf: + if not options.psfonts: + warning (_ ("option --psfonts not used")) + warning (_ ("processing with dvips will have no fonts")) + else: + progress ('\n') + progress (_ ("DVIPS usage:")) + progress ('\n') + progress (" dvips -h %(psfonts_file)s %(output)s" % vars ()) + progress ('\n') + def main (): + # FIXME: 85 lines of `main' macramee?? files = do_options () file = files[0] @@ -1695,7 +1813,7 @@ def main (): global_options.format = guess_format (files[0]) formats = 'ps' - if global_options.format in (TEXINFO, HTML): + if global_options.format in (TEXINFO, HTML, DOCBOOK): formats += ',png' @@ -1704,15 +1822,23 @@ def main (): + ' --formats=%s --backend eps ' % formats) if global_options.process_cmd: - global_options.process_cmd += string.join ([(' -I %s' % commands.mkarg (p)) + global_options.process_cmd += string.join ([(' -I %s' % ly.mkarg (p)) for p in global_options.include_path]) - if (global_options.format in (TEXINFO, LATEX) - and global_options.create_pdf): - global_options.process_cmd += "--pdf -deps-font-include -dgs-font-load " - + if global_options.format in (TEXINFO, LATEX): + ## prevent PDF from being switched on by default. + 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.verbose: global_options.process_cmd += " --verbose " + + if global_options.padding_mm: + global_options.process_cmd += " -deps-box-padding=%f " % global_options.padding_mm + + global_options.process_cmd += " -dread-file-list " + identify () try: @@ -1735,19 +1861,7 @@ def main (): except Compile_error: exit (1) - if global_options.format in (TEXINFO, LATEX): - psfonts_file = os.path.join (global_options.output_name, basename + '.psfonts') - output = os.path.join (global_options.output_name, basename + '.dvi' ) - - if not global_options.psfonts and not global_options.create_pdf: - warning (_ ("option --psfonts not used")) - warning (_ ("processing with dvips will have no fonts")) - else: - progress ('\n') - progress (_ ("DVIPS usage:")) - progress ('\n') - progress (" dvips -h %(psfonts_file)s %(output)s" % vars ()) - progress ('\n') + psfonts_warning (global_options, basename) inputs = note_input_file ('') inputs.pop ()