'''
import stat
-import string
import tempfile
import commands
import os
import sys
import re
+import md5
+import operator
-################
-# 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])
-
-os.environ['PATH'] = bindir + os.pathsep + os.environ['PATH']
-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
original_dir = os.getcwd ()
backend = 'ps'
-help_summary = _ (
-'''Process LilyPond snippets in hybrid HTML, LaTeX, texinfo or DocBook 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 <janneke@gnu.org>',
- 'Han-Wen Nienhuys <hanwen@cs.uu.nl>')
+ 'Han-Wen Nienhuys <hanwen@xs4all.nl>')
-
################################################################
def exit (i):
if global_options.verbose:
- raise _ ('Exiting (%d)...') % i
+ raise Exception (_ ('Exiting (%d)...') % i)
else:
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)
m = re.search ('\n%%Pages: ([0-9]+)', header)
if m:
- return string.atoi (m.group (1))
+ return int (m.group (1))
return 0
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',
- version="@TOPLEVEL_VERSION@",
- description=help_summary)
+ p = ly.get_option_parser (usage=_ ("%s [OPTION]... FILE") % 'lilypond-book',
+ description=help_summary,
+ add_help_option=False)
p.add_option ('-F', '--filter', metavar=_ ("FILTER"),
action="store",
dest="filter_cmd",
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, docbook)'''),
+ 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("-h", "--help",
+ action="help",
+ help=_ ("show this help and exit"))
+
+ 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'''),
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.version = "@TOPLEVEL_VERSION@"
+ p.add_option("--version",
+ action="version",
+ help=_ ("show version number and exit"))
+
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 (ly.display_encode (_ ('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')
#
# Is this pythonic? Personally, I find this rather #define-nesque. --hwn
#
+ADDVERSION = 'addversion'
AFTER = 'after'
BEFORE = 'before'
DOCBOOK = 'docbook'
LATEX = 'latex'
LAYOUT = 'layout'
LINE_WIDTH = 'line-width'
+LILYQUOTE = 'lilyquote'
NOFRAGMENT = 'nofragment'
NOINDENT = 'noindent'
NOQUOTE = 'noquote'
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''',
OUTPUTIMAGE: r'''@noindent
@ifinfo
-@image{%(base)s,,,%(alt)s,%(ext)s}
+@image{%(info_image_path)s,,,%(alt)s,%(ext)s}
@end ifinfo
@html
<p>
@verbatim
%(verb)s@end verbatim
''',
+
+ ADDVERSION: r'''\version @w{"@version{}"}
+%(verb)s'''
},
}
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 {
return (None, None)
-def find_file (name):
+def find_file (name, raise_error=True):
for i in global_options.include_path:
full = os.path.join (i, name)
if os.path.exists (full):
return full
- error (_ ("file not found: %s") % name + '\n')
- exit (1)
+ if raise_error:
+ error (_ ("file not found: %s") % name + '\n')
+ exit (1)
return ''
def verbatim_html (s):
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'
option_list.append (key)
else:
option_list.append (key + '=' + value)
- option_string = string.join (option_list, ',')
+ option_string = ','.join (option_list)
compose_dict = {}
compose_types = [NOTES, PREAMBLE, LAYOUT, PAPER]
elif relative > 0:
relative_quotes += "'" * relative
- paper_string = string.join (compose_dict[PAPER],
- '\n ') % override
- layout_string = string.join (compose_dict[LAYOUT],
- '\n ') % override
- notes_string = string.join (compose_dict[NOTES],
- '\n ') % vars ()
- preamble_string = string.join (compose_dict[PREAMBLE],
- '\n ') % override
-
+ 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 = global_options.padding_mm
font_dump_setting = ''
if FONTLOAD in self.option_dict:
font_dump_setting = '#(define-public force-eps-font-include #t)\n'
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 = find_file (base + '.ly', raise_error=False)
+ tex_file = find_file (base + '.tex', raise_error=False)
+ systems_file = find_file (base + '-systems.tex', raise_error=False)
+
+ 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 ()
- ok = not self.ly_is_outdated ()
- if global_options.format in (HTML, TEXINFO):
- ok = ok and os.path.exists (base + '.eps')
-
- page_count = 0
- if ok:
- page_count = ps_page_count (base + '.eps')
-
- if page_count <= 1:
- ok = ok and os.path.exists (base + '.png')
-
- elif page_count > 1:
- for a in range (1, page_count + 1):
- ok = ok and os.path.exists (base + '-page%d.png' % a)
-
- return not ok
+ eps_file = find_file (base + '.eps', raise_error=False)
+ png_file = find_file (base + '.png', raise_error=False)
+ if not self.ly_is_outdated () and global_options.format in (HTML, TEXINFO):
+ if os.path.exists (eps_file):
+ page_count = ps_page_count (eps_file)
+ if page_count <= 1:
+ return not os.path.exists (png_file)
+ else:
+ return not reduce (operator.or_,
+ [find_file (base + '-page%d.png' % a, raise_error=False)
+ for a in range (1, page_count + 1)])
+ return True
def texstr_is_outdated (self):
if backend == 'ps':
return 0
base = self.basename ()
- ok = self.ly_is_outdated ()
- ok = ok and (os.path.exists (base + '.texstr'))
- return not ok
+ return not (self.ly_is_outdated ()
+ and find_file (base + '.texstr', raise_error=False))
def filter_text (self):
code = self.substring ('code')
else:
str = '<mediaobject>' + str + '</mediaobject>'
if VERBATIM in self.option_dict:
- verb = verbatim_html (self.substring ('code'))
+ verb = verbatim_html (self.verb_ly ())
str = output[DOCBOOK][VERBATIM] % vars () + str
return str
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 ()
# 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 ()
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 ())
str = ''
if PRINTFILENAME in self.option_dict:
base = self.basename ()
- filename = self.substring ('filename')
- str = output[global_options.format][PRINTFILENAME] % vars ()
+ filename = os.path.basename (self.substring ('filename'))
+ str = output[format][PRINTFILENAME] % vars ()
return str
def output_texinfo (self):
- str = ''
- if self.output_print_filename (TEXINFO):
- str += ('@html\n'
- + self.output_print_filename (HTML)
- + '\n@end html\n')
- str += ('@tex\n'
- + self.output_print_filename (LATEX)
- + '\n@end tex\n')
+ str = self.output_print_filename (TEXINFO)
base = self.basename ()
if TEXIDOC in self.option_dict:
texidoc = base + '.texidoc'
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 ()
+ if ADDVERSION in self.option_dict:
+ verb = output[TEXINFO][ADDVERSION] % vars ()
+ 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')
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,
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:
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 '
- if global_options.format in (DOCBOOK):
+ 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.
if texstr_names:
- my_system (string.join ([cmd, '--backend texstr',
- 'snippet-map.ly'] + texstr_names))
+ my_system (' '.join ([cmd, '--backend texstr',
+ 'snippet-map.ly'] + texstr_names))
for l in texstr_names:
my_system ('latex %s.texstr' % l)
if ly_names:
open ('snippet-names', 'wb').write ('\n'.join (['snippet-map.ly']
- + ly_names))
+ + ly_names))
- my_system (string.join ([cmd, 'snippet-names']))
+ my_system (' '.join ([cmd, 'snippet-names']))
LATEX_INSPECTION_DOCUMENT = r'''
def get_latex_textwidth (source):
m = re.search (r'''(?P<preamble>\\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
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:
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__,
# FIXME
format = ext2format[e]
else:
- error (_ ("can't determine format for: %s" \
+ error (_ ("cannot determine format for: %s" \
% input_filename))
exit (1)
return format
try:
f = open (file_name)
oldstr = f.read ()
- new_str = string.join (lines, '')
+ new_str = ''.join (lines)
if oldstr == new_str:
progress (_ ("%s is up to date.") % file_name)
progress ('\n')
+
+ # this prevents make from always rerunning lilypond-book:
+ # .texi target must be touched in order to be up to date
+ if global_options.format == 'texinfo':
+ os.utime (file_name, None)
return
except:
pass
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]
+ ' --formats=%s --backend eps ' % formats)
if global_options.process_cmd:
- global_options.process_cmd += string.join ([(' -I %s' % ly.mkarg (p))
+ global_options.process_cmd += ' '.join ([(' -I %s' % ly.mkarg (p))
for p in global_options.include_path])
if global_options.format in (TEXINFO, LATEX):
## prevent PDF from being switched on by default.
global_options.process_cmd += ' --formats=eps '
-
- if (global_options.format in (TEXINFO, LATEX)
- and global_options.create_pdf):
- global_options.process_cmd += "--pdf -dinclude-eps-fonts -dgs-load-fonts "
-
-
+ 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 "
- global_options.process_cmd += " -dread-file-list -deps-box-padding=-3 "
+ 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 ()
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 ()