]> git.donarmstrong.com Git - lilypond.git/blobdiff - scripts/ly2dvi.py
* Documentation/user/invoking.itexi (Invoking the lilypond
[lilypond.git] / scripts / ly2dvi.py
index 72d0fe1516ffe4eb608e92288db09edcf0b499aa..dc3725b11700494696dd73f0eb48df99edfee554 100644 (file)
@@ -6,7 +6,7 @@
 # 
 # source file of the GNU LilyPond music typesetter
 # 
-# (c) 1998--2002  Han-Wen Nienhuys <hanwen@cs.uu.nl>
+# (c)  1998--2003  Han-Wen Nienhuys <hanwen@cs.uu.nl>
 #                 Jan Nieuwenhuizen <janneke@gnu.org>
 
 # This is the third incarnation of ly2dvi.
@@ -32,11 +32,12 @@ TODO:
       default: create dvi only
       na: create tex, latex and dvi
       -P: create dvi and ps
+      -p: create pdf
       na: * create ps only
 
      etc.
 
-     for foo.ly, rename ly2dvi.dir to out-ly2dvi, foo.ly2dvi, foo.dir ?
+  * for foo.ly, rename ly2dvi.dir to out-ly2dvi, foo.ly2dvi, foo.dir ?
      
   * move versatile taglines, 
   
@@ -45,7 +46,8 @@ TODO:
         endfooter=\tagline  -> 'lily was here <version>'
      }
 
-     lilytagline (->lily was here), usertagline, copyright etc.
+     lilytagline (->lily was here), usertagline, copyright, lily-version
+     etc.
 
   * head/header tagline/endfooter
 
@@ -53,13 +55,25 @@ TODO:
     from lilypond .tex *and* header output.
 
   * multiple \score blocks?
+
+  * Introduce verbosity levels
   
+     0  = QUIET: mute all command output, no ly2dvi progress
+     1  = BRIEF: mute all command output, only ly2dvi progress
+     2a = NORMAL: show only LilyPond command output, show ly2dvi progress
+     2b = NORMAL: show command output, show ly2dvi progress
+     3  = VERBOSE: show command output, run lilypond --verbose
+     4  = DEBUGGING: show all command output, run lilypond --verbose, print
+                   environment and all kinds of client side debugging stuff
+
+     Currently, we only have 1 and 4, but we kludge to have 2a and 4.
 '''
 
 import operator
 import stat
 import string
 import traceback
+import glob
 
 ################################################################
 # Users of python modules should include this snippet
@@ -81,6 +95,7 @@ if os.environ.has_key ('LILYPONDPREFIX') :
        while datadir[-1] == os.sep:
                datadir= datadir[:-1]
 
+
 sys.path.insert (0, os.path.join (datadir, 'python'))
 
 # Customize these
@@ -92,12 +107,14 @@ global re;re = ly.re
 
 # lilylib globals
 program_name = 'ly2dvi'
+program_version = '@TOPLEVEL_VERSION@'
 verbose_p = 0
 pseudo_filter_p = 0
 original_dir = os.getcwd ()
 temp_dir = os.path.join (original_dir,  '%s.dir' % program_name)
 keep_temp_dir_p = 0
 preview_resolution = 90
+debug_p = 0
 
 ## FIXME
 ## ly2dvi: silly name?
@@ -111,6 +128,7 @@ option_definitions = [
        ('', 'd', 'dependencies',
         _ ("write Makefile dependencies for every input file")),
        ('', 'h', 'help', _ ("this help")),
+       ('', '', 'debug', _ ("print even more output")),
        (_ ("DIR"), 'I', 'include', _ ("add DIR to LilyPond's search path")),
        ('', 'k', 'keep',
         _ ("keep all output, output to directory %s.dir") % program_name),
@@ -121,10 +139,13 @@ option_definitions = [
        (_ ('RES'), '', 'preview-resolution',
         _ ("set the resolution of the preview to RES")),
        ('', 'P', 'postscript', _ ("generate PostScript output")),
-       ('', 'p', 'pdf', _ ("generate PDF output")),    
+       ('', '', 'png', _("generate PNG page images")),
+       ('', '', 'psgz', _("generate PS.GZ")), 
+       ('', 'p', 'pdf', _ ("generate PDF output")),
        ('', '', 'pdftex', _ ("use pdflatex to generate a PDF output")),
        # FIXME: preview, picture; to indicate creation of a PNG?
        ('', '', 'preview', _ ("make a picture of the first system")),
+       ('','', 'html', _("make HTML file with links to all output")),
        (_ ("KEY=VAL"), 's', 'set', _ ("change global setting KEY to VAL")),
        ('', 'V', 'verbose', _ ("verbose")),
        ('', 'v', 'version', _ ("print version number")),
@@ -133,16 +154,24 @@ option_definitions = [
 
 # other globals
 preview_p = 0
+page_images_p = 0
 lilypond_error_p = 0
+html_p = 0
 
 # Pdftex support
 pdftex_p = 0
 latex_cmd = 'latex'
-tex_extension = '.tex'
 
-# Debugging support -- do we need this?
-lilypond_cmd = 'lilypond'
-#lilypond_cmd = 'valgrind --suppressions=%(home)s/usr/src/guile-1.6.supp --num-callers=10 %(home)s/usr/src/lilypond/lily/out/lilypond '% { 'home' : '/home/hanwen' }
+
+tex_extension = '.tex'  ## yuk.
+
+#lilypond_binary = 'valgrind --suppressions=%(home)s/usr/src/guile-1.6.supp --num-callers=10 %(home)s/usr/src/lilypond/lily/out/lilypond '% { 'home' : '/home/hanwen' }
+
+lilypond_binary = os.path.join ('@bindir@', 'lilypond')
+
+# only use installed binary  when we're installed too.
+if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary):
+       lilypond_binary = 'lilypond'
 
 
 layout_fields = ['dedication', 'title', 'subtitle', 'subsubtitle',
@@ -157,7 +186,10 @@ extra_init = {
        'language' : [],
        'latexheaders' : [],
        'latexpackages' :  ['geometry'],
-       'latexoptions' : [],
+
+       # for geometry v3
+       'latexoptions' : ['compat2'],
+       
        'papersize' : [],
        'pagenumber' : [1],
        'textheight' : [], 
@@ -229,16 +261,12 @@ def run_lilypond (files, dep_prefix):
        global verbose_p
        if verbose_p:
                opts = opts + ' --verbose'
-               ly.print_environment ()
-
-       cmd = string.join ((lilypond_cmd,opts, fs))
-       
-       # We unset verbose, because we always want to see lily's
-       # progess on stderr
-       save_verbose = verbose_p
-       status = ly.system (cmd, ignore_error = 1)
-       verbose_p = save_verbose
 
+       if debug_p:
+               ly.print_environment ()
+               
+       cmd = string.join ((lilypond_binary, opts, fs))
+       status = ly.system (cmd, ignore_error = 1, progress_p = 1)
        signal = 0x0f & status
        exit_status = status >> 8
 
@@ -266,7 +294,7 @@ def analyse_lilypond_output (filename, extra):
        # urg
        '''Grep FILENAME for interesting stuff, and
        put relevant info into EXTRA.'''
-       filename = filename+tex_extension
+       filename = filename + tex_extension
        ly.progress (_ ("Analyzing %s...") % filename)
        s = open (filename).read ()
 
@@ -279,24 +307,25 @@ def analyse_lilypond_output (filename, extra):
        ly.progress ('\n')
 
 def find_tex_files_for_base (base, extra):
-
        '''
        Find the \header fields dumped from BASE.
        '''
        
        headerfiles = {}
        for f in layout_fields:
-               if os.path.exists (base + '.' + f):
-                       headerfiles[f] = base+'.'+f
+               fn = base + '.' + f
+               if os.path.exists (fn):
+                       headerfiles[f] = fn
 
        if os.path.exists (base  +'.dep'):
                dependency_files.append (base + '.dep')
 
        for f in extra_fields:
-               if os.path.exists (base + '.' + f):
-                       extra[f].append (open (base + '.' + f).read ())
+               fn =base + '.' + f
+               if os.path.exists (fn):
+                       extra[f].append (open (fn).read ())
        
-       return (base+tex_extension,headerfiles)
+       return (base + tex_extension, headerfiles)
         
 
 def find_tex_files (files, extra):
@@ -347,9 +376,11 @@ def one_latex_definition (defn, first):
 
 
 ly_paper_to_latexpaper =  {
-       'a4' : 'a4paper',
        'letter' : 'letterpaper', 
-       'a3' : 'a3paper'
+       'a3' : 'a3paper',
+       'a4' : 'a4paper',
+       'a5' : 'a5paper',
+       'a6' : 'a6paper',
 }
 
 #TODO: should set textheight (enlarge) depending on papersize. 
@@ -461,6 +492,9 @@ None
        f.close ()
 
        cmd = latex_cmd + ' \\\\nonstopmode \\\\input %s' % latex_fn
+       # Ugh.  (La)TeX writes progress and error messages on stdout
+       # Redirect to stderr
+       cmd += ' 1>/dev/stderr'
        status = ly.system (cmd, ignore_error = 1)
        signal = 0xf & status
        exit_status = status >> 8
@@ -482,23 +516,25 @@ None
                ly.exit (1)
        
        if preview_p:
-               # make a preview by rendering only the 1st line.
-               preview_fn = outbase + '.preview.tex'
-               f = open (preview_fn, 'w')
-               f.write (r'''
-%s
-\input lilyponddefs
-\pagestyle{empty}
-\begin{document}
-\def\interscoreline{\endinput}
-\input %s
-\end{document}
-''' % (global_latex_preamble (extra), outbase))
-
-               f.close()
-               cmd = '%s \\\\nonstopmode \\\\input %s' % (latex_cmd, preview_fn)
-               ly.system (cmd)
-       
+               # make a preview by rendering only the 1st line
+               # of each score
+               for score in find_tex_files (files, extra):
+                       preview_base = ly.strip_extension (score[0], '.tex')
+                       preview_fn = preview_base + '.preview.tex'
+                       s = global_latex_definition ((score,), extra)
+                       s = re.sub ('thispagestyle{firstpage}',
+                                   r'''thispagestyle{empty}%
+                                   \\def\\interscoreline{\\endinput}''', s)
+                       s = re.sub ('thispagestyle{lastpage}',
+                                   r'''thispagestyle{empty}%
+                                   \\def\\interscoreline{\\endinput}''', s)
+                       f = open (preview_fn, 'w')
+                       f.write (s)
+                       f.close ()
+                       cmd = '%s \\\\nonstopmode \\\\input %s' \
+                             % (latex_cmd, preview_fn)
+                       ly.system (cmd)
+
 
 def run_dvips (outbase, extra):
 
@@ -517,15 +553,33 @@ None.
        if extra['orientation'] and extra['orientation'][0] == 'landscape':
                opts = opts + ' -tlandscape'
 
+
        if 'PDF' in targets:
-               opts = opts + ' -Ppdf -G0 -u lilypond.map'
-               
+               where = ly.read_pipe ('kpsewhich feta20.pfa').strip()
+
+               pfa_file  = None
+               if where:
+                       try: 
+                               pfa_file = open (where, 'r')
+                       except IOError:
+                               pass
+
+               if pfa_file:
+                       opts = opts + ' -Ppdf -G0 -u +lilypond.map'
+               else:
+                       ly.warning (_ ('''Trying create PDF, but no PFA fonts found.
+Using bitmap fonts instead. This will look bad.'''))
+
        cmd = 'dvips %s -o%s %s' % (opts, outbase + '.ps', outbase + '.dvi')
        ly.system (cmd)
 
        if preview_p:
-               cmd = 'dvips -E -o%s %s' % ( outbase + '.preview.ps', outbase + '.preview.dvi')         
-               ly.system (cmd)
+               for score in find_tex_files (files, extra):
+                       preview_base = ly.strip_extension (score[0], '.tex')
+                       cmd = 'dvips -E -o%s %s' \
+                             % (preview_base + '.preview.ps',
+                                preview_base + '.preview.dvi')
+                       ly.system (cmd)
 
        if 'PDF' in targets:
                cmd = 'ps2pdf %s.ps %s.pdf' % (outbase , outbase)
@@ -571,7 +625,48 @@ def find_pfa_fonts (name):
                m = re.match ('.*?/(feta[-a-z0-9]+) +findfont', s[here:], re.DOTALL)
        return pfa
 
+
+def make_html_menu_file (html_file, files_found):
+       exts = {
+               'pdf' : "Print (PDF, %s)",
+               'ps.gz' : "Print (gzipped PostScript, %s)",
+               'png' : "View (PNG, %s)",
+               'midi' : "Listen (MIDI, %s)",
+               'ly' : "View source code (%s)", 
+               }
+       html_str = ''
+
+       pages = filter (lambda x : re.search ('page[0-9]+.png',  x),
+                       files_found)
+       rest =  filter (lambda x : not re.search ('page[0-9]+.png',  x),
+                       files_found)
+
+       preview = filter (lambda x: re.search ('.png$', x), rest)
+       if preview:
+               html_str = '<img src="%s">' % preview[0]
+
+       for p in pages:
+               page = re.sub ('.*page([0-9])+.*', 'View page \\1 (PNG picture, %s)\n', p)
+               page = page % 'unknown size'
+               
+               html_str += '<li><a href="%s">%s</a>' % (p, page)
+               
+               
+       for e in ['pdf', 'ps.gz', 'midi', 'ly']:
+               fs = filter (lambda x: re.search ('.%s$' % e, x), rest)
+               for f in fs:
+                       entry = exts[e] % 'unknown size' # todo
+                       html_str += '<li><a href="%s">%s</a>\n\n' % (f, entry)
+
+       html_str += "\n\n</li>"
+       ly.progress (_("Writing HTML menu `%s'") % html_file)
+       ly.progress ('\n')
+       open (html_file, 'w').write (html_str)
        
+################################################################
+## MAIN
+################################################################
+
 (sh, long) = ly.getopt_args (option_definitions)
 try:
        (options, files) = getopt.getopt (sys.argv[1:], sh, long)
@@ -607,11 +702,15 @@ for opt in options:
                targets.append ('PDF')
        elif o == '--keep' or o == '-k':
                keep_temp_dir_p = 1
+       elif o == '--debug':
+               verbose_p = 1
+               debug_p = 1 
        elif o == '--no-lily':
                lily_p = 0
        elif o == '--preview':
                preview_p = 1
-               targets.append ('PNG')
+               if 'PNG' not in targets:
+                       targets.append ('PNG')
        elif o == '--preview-resolution':
                preview_resolution = string.atoi (a)
        elif o == '--no-paper' or o == '-m':
@@ -636,10 +735,20 @@ for opt in options:
                pdftex_p = 1
                tex_extension = '.pdftex'
        elif o == '--warranty' or o == '-w':
-               status = os.system ('lilypond -w')
+               status = os.system ('%s -w' % lilypond_binary)
                if status:
                        ly.warranty ()
                sys.exit (0)
+       elif o == '--html':
+               html_p = 1
+       elif o == '--png':
+               page_images_p = 1
+               if 'PNG' not in targets:
+                       targets.append ('PNG')
+       elif o == '--psgz':
+               targets.append ('PS.GZ')
+       else:
+               unimplemented_option () # signal programming error
 
 # Don't convert input files to abspath, rather prepend '.' to include
 # path.
@@ -672,6 +781,8 @@ if not files:
 
 if 1:
        ly.identify (sys.stderr)
+       ly.lilypond_version_check (lilypond_binary, '@TOPLEVEL_VERSION@')
+       
        original_output = output_name
        
        # Ugh, maybe make a setup () function
@@ -724,23 +835,26 @@ if 1:
                try:
                        run_lilypond (files, dep_prefix)
                except:
+                       ### ARGH. This also catches python programming errors.
+                       ### this should only catch lilypond nonzero exit  status
+                       ### --hwn
+
+                       
                        # TODO: friendly message about LilyPond setup/failing?
                        #
-                       # TODO: lilypond should fail with different
-                       # error codes for:
-                       #   - guile setup/startup failure
-                       #   - font setup failure
-                       #   - init.ly setup failure
-                       #   - parse error in .ly
-                       #   - unexpected: assert/core dump
                        targets = []
                        if verbose_p:
                                traceback.print_exc ()
-
+                       else:
+                               ly.warning (_("Running LilyPond failed. Rerun with --verbose for a trace."))
+                               
        # Our LilyPond pseudo filter always outputs to 'lelie'
        # have subsequent stages and use 'lelie' output.
        if pseudo_filter_p:
                files[0] = 'lelie'
+
+       if 'PS.GZ'  in targets:
+               targets.append ('PS')
                
        if 'PNG' in targets and 'PS' not in targets:
                targets.append ('PS')
@@ -766,14 +880,21 @@ if 1:
        if 'PS' in targets:
                try:
                        run_dvips (outbase, extra_init)
+                       
                except: 
                        if 'PS' in targets:
                                targets.remove ('PS')
                        if verbose_p:
                                traceback.print_exc ()
+                       else:
+                               ly.warning (_("Failed to make PS file. Rerun with --verbose for a trace."))
 
-       if 'PNG' in  targets:
-               ly.make_preview (outbase)
+       if preview_p:
+               for score in find_tex_files (files, extra_init):
+                       preview_base = ly.strip_extension (score[0], '.tex')
+                       ly.make_ps_images (preview_base + '.preview.ps',
+                                          resolution=preview_resolution
+                                          )
 
        if 'PDFTEX' in targets:
                try:
@@ -795,6 +916,11 @@ if 1:
                                targets.remove ('PS')
                        if verbose_p:
                                traceback.print_exc ()
+                       else:
+                               ly.warning (_("Running LaTeX failed. Rerun with --verbose for a trace."))
+                               
+       if page_images_p:
+               ly.make_ps_images (outbase + '.ps' )
 
        # add DEP to targets?
        if track_dependencies_p:
@@ -802,7 +928,7 @@ if 1:
                generate_dependency_file (depfile, depfile)
                if os.path.isfile (depfile):
                        ly.progress (_ ("dependencies output to `%s'...") %
-                                 depfile)
+                                    depfile)
                        ly.progress ('\n')
 
        if pseudo_filter_p:
@@ -821,20 +947,34 @@ if 1:
                targets = []
                ly.progress ('\n')
                
+       if 'PS.GZ' in targets:
+               ly.system ("gzip *.ps") 
+               targets.remove ('PS')
+
        # Hmm, if this were a function, we could call it the except: clauses
+       files_found = []
        for i in targets:
                ext = string.lower (i)
+
+               pattern = '%s.%s' % (outbase, ext)
+               if i == 'PNG':
+                       pattern  = '*.png' 
+               ls = glob.glob (pattern)
+               files_found += ls 
                ly.cp_to_dir ('.*\.%s$' % ext, outdir)
-               outname = outbase + '.' + string.lower (i)
-               abs = os.path.join (outdir, outname)
-               if reldir != '.':
-                       outname = os.path.join (reldir, outname)
-               if os.path.isfile (abs):
-                       ly.progress (_ ("%s output to `%s'...") % (i, outname))
+
+
+               if ls:
+                       names = string.join (map (lambda x: "`%s'" % x, ls))
+                       ly.progress (_ ("%s output to %s...") % (i, names))
                        ly.progress ('\n')
                elif verbose_p:
                        ly.warning (_ ("can't find file: `%s'") % outname)
-                       
+
+       if html_p:
+               make_html_menu_file (os.path.join (outdir, outbase + ".html"),
+                                    files_found)
+
        os.chdir (original_dir)
        ly.cleanup_temp ()