]> git.donarmstrong.com Git - lilypond.git/blob - scripts/ly2dvi.py
release: 1.5.4
[lilypond.git] / scripts / ly2dvi.py
1 #!@PYTHON@
2 # Run lilypond, latex, dvips.
3 #
4 # This is the third incarnation of ly2dvi.
5 #
6 # Earlier incarnations of ly2dvi were written by
7 # Jeffrey B. Reed<daboys@austin.rr.com> (Python version)
8 # Jan Arne Fagertun <Jan.A.Fagertun@@energy.sintef.no> (Bourne shell script)
9 #
10
11
12
13 # TODO: should allow to set a central pk cache directory from the command line.
14 # TODO: should allow to switch off pk cache.
15 #
16
17
18 # Note: gettext work best if we use ' for docstrings and "
19 #       for gettextable strings.
20 #       --> DO NOT USE """ for docstrings.
21
22 '''
23 TODO:
24
25   * figure out which set of command line options should make ly2dvi:
26
27       na: create tex only?  
28       na: create latex only? 
29       na: create tex and latex
30       default: create dvi only
31       na: create tex, latex and dvi
32       -P: create dvi and ps
33       na: * create ps only
34
35      etc.
36
37      for foo.ly, rename ly2dvi.dir to out-ly2dvi, foo.ly2dvi, foo.dir ?
38      
39   * move versatile taglines, 
40   
41      \header {
42         beginfooter=\mutopiaPD
43         endfooter=\tagline  -> 'lily was here <version>'
44      }
45
46      lilytagline (->lily was here), usertagline, copyright etc.
47
48   * head/header tagline/endfooter
49
50   * dvi from lilypond .tex output?  This is hairy, because we create dvi
51     from lilypond .tex *and* header output.
52
53   * multiple \score blocks?
54   
55 '''
56
57
58 import os
59 import stat
60 import string
61 import re
62 import getopt
63 import sys
64 import shutil
65 import __main__
66 import operator
67 import tempfile
68 import traceback
69
70 datadir = '@datadir@'
71 sys.path.append (datadir + '/python')
72 try:
73         import gettext
74         gettext.bindtextdomain ('lilypond', '@localedir@')
75         gettext.textdomain('lilypond')
76         _ = gettext.gettext
77 except:
78         def _ (s):
79                 return s
80
81
82 layout_fields = ['dedication', 'title', 'subtitle', 'subsubtitle',
83           'footer', 'head', 'composer', 'arranger', 'instrument',
84           'opus', 'piece', 'metre', 'meter', 'poet', 'texttranslator']
85
86
87 # init to empty; values here take precedence over values in the file
88
89 ## TODO: change name.
90 extra_init = {
91         'language' : [],
92         'latexheaders' : [],
93         'latexpackages' :  ['geometry'],
94         'latexoptions' : [],
95         'papersize' : [],
96         'pagenumber' : [1],
97         'textheight' : [], 
98         'linewidth' : [],
99         'orientation' : []
100 }
101
102 extra_fields = extra_init.keys ()
103
104 fields = layout_fields + extra_fields
105 program_name = 'ly2dvi'
106 help_summary = _ ("Generate .dvi with LaTeX for LilyPond")
107
108 include_path = ['.']
109 lily_p = 1
110 paper_p = 1
111 cache_pks_p = 1
112
113 PK_PATTERN='feta.*\.[0-9]+pk'
114
115 output_name = ''
116 targets = {
117         'DVI' : 0,
118         'LATEX' : 0,
119         'MIDI' : 0,
120         'TEX' : 0,
121         }
122
123 track_dependencies_p = 0
124 dependency_files = []
125
126
127 # lily_py.py -- options and stuff
128
129 # source file of the GNU LilyPond music typesetter
130
131 # BEGIN Library for these?
132 # cut-n-paste from ly2dvi
133
134 program_version = '@TOPLEVEL_VERSION@'
135 if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
136         program_version = '1.3.148'
137
138
139 original_dir = os.getcwd ()
140 temp_dir = os.path.join (original_dir,  '%s.dir' % program_name)
141
142 keep_temp_dir_p = 0
143 verbose_p = 0
144
145 #
146 # Try to cater for bad installations of LilyPond, that have
147 # broken TeX setup.  Just hope this doesn't hurt good TeX
148 # setups.  Maybe we should check if kpsewhich can find
149 # feta16.{afm,mf,tex,tfm}, and only set env upon failure.
150 #
151 environment = {
152         'MFINPUTS' : datadir + '/mf' + ':',
153         'TEXINPUTS': datadir + '/tex:' + datadir + '/ps' + ':',
154         'TFMFONTS' : datadir + '/tfm' + ':',
155         'GS_FONTPATH' : datadir + '/afm:' + datadir + '/pfa',
156         'GS_LIB' : datadir + '/ps',
157 }
158
159 def setup_environment ():
160         for key in environment.keys ():
161                 val = environment[key]
162                 if os.environ.has_key (key):
163                         val = os.environ[key] + os.pathsep + val 
164                 os.environ[key] = val
165
166 def identify ():
167         sys.stdout.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version))
168
169 def warranty ():
170         identify ()
171         sys.stdout.write ('\n')
172         sys.stdout.write (_ ('Copyright (c) %s by' % ' 2001'))
173         sys.stdout.write ('\n')
174         sys.stdout.write ('  Han-Wen Nienhuys')
175         sys.stdout.write ('  Jan Nieuwenhuizen')
176         sys.stdout.write ('\n')
177         sys.stdout.write (_ (r'''
178 Distributed under terms of the GNU General Public License. It comes with
179 NO WARRANTY.'''))
180         sys.stdout.write ('\n')
181
182 if ( os.name == 'posix' ):
183         errorport=sys.stderr
184 else:
185         errorport=sys.stdout
186
187 def progress (s):
188         errorport.write (s + '\n')
189
190 def warning (s):
191         progress (_ ("warning: ") + s)
192                 
193 def error (s):
194
195
196         '''Report the error S.  Exit by raising an exception. Please
197         do not abuse by trying to catch this error. If you do not want
198         a stack trace, write to the output directly.
199
200         RETURN VALUE
201
202         None
203         
204         '''
205         
206         progress (_ ("error: ") + s)
207         raise _ ("Exiting ... ")
208
209 def getopt_args (opts):
210         '''Construct arguments (LONG, SHORT) for getopt from  list of options.'''
211         short = ''
212         long = []
213         for o in opts:
214                 if o[1]:
215                         short = short + o[1]
216                         if o[0]:
217                                 short = short + ':'
218                 if o[2]:
219                         l = o[2]
220                         if o[0]:
221                                 l = l + '='
222                         long.append (l)
223         return (short, long)
224
225 def option_help_str (o):
226         '''Transform one option description (4-tuple ) into neatly formatted string'''
227         sh = '  '       
228         if o[1]:
229                 sh = '-%s' % o[1]
230
231         sep = ' '
232         if o[1] and o[2]:
233                 sep = ','
234                 
235         long = ''
236         if o[2]:
237                 long= '--%s' % o[2]
238
239         arg = ''
240         if o[0]:
241                 if o[2]:
242                         arg = '='
243                 arg = arg + o[0]
244         return '  ' + sh + sep + long + arg
245
246
247 def options_help_str (opts):
248         '''Convert a list of options into a neatly formatted string'''
249         w = 0
250         strs =[]
251         helps = []
252
253         for o in opts:
254                 s = option_help_str (o)
255                 strs.append ((s, o[3]))
256                 if len (s) > w:
257                         w = len (s)
258
259         str = ''
260         for s in strs:
261                 str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0])  + 3), s[1])
262         return str
263
264 def help ():
265         ls = [(_ ("Usage: %s [OPTION]... FILE") % program_name),
266                 ('\n\n'),
267                 (help_summary),
268                 ('\n\n'),
269                 (_ ("Options:")),
270                 ('\n'),
271                 (options_help_str (option_definitions)),
272                 ('\n\n'),
273                 (_ ("Report bugs to %s") % 'bug-gnu-music@gnu.org'),
274                 ('\n')]
275         map (sys.stdout.write, ls)
276         
277 def setup_temp ():
278         """
279         Create a temporary directory, and return its name. 
280         """
281         global temp_dir
282         if not keep_temp_dir_p:
283                 temp_dir = tempfile.mktemp (program_name)
284         try:
285                 os.mkdir (temp_dir, 0777)
286         except OSError:
287                 pass
288
289         return temp_dir
290
291
292 def system (cmd, ignore_error = 0):
293         """Run CMD. If IGNORE_ERROR is set, don't complain when CMD returns non zero.
294
295         RETURN VALUE
296
297         Exit status of CMD
298         """
299         
300         if ( os.name != 'posix' ):
301                 cmd = re.sub (r'''\\''', r'''\\\\\\''', cmd)
302                 cmd = "sh -c \'%s\'" % cmd
303
304                 
305         if verbose_p:
306                 progress (_ ("Invoking `%s\'") % cmd)
307         st = os.system (cmd)
308         if st:
309                 name = re.match ('[ \t]*([^ \t]*)', cmd).group (1)
310                 msg = name + ': ' + _ ("command exited with value %d") % st
311                 if ignore_error:
312                         warning (msg + ' ' + _ ("(ignored)") + ' ')
313                 else:
314                         error (msg)
315
316         return st
317
318
319 def cleanup_temp ():
320         if not keep_temp_dir_p:
321                 if verbose_p:
322                         progress (_ ("Cleaning %s...") % temp_dir)
323                 shutil.rmtree (temp_dir)
324
325
326 #what a name.
327 def set_setting (dict, key, val):
328         try:
329                 val = string.atof (val)
330         except ValueError:
331                 #warning (_ ("invalid value: %s") % `val`)
332                 pass
333
334         try:
335                 dict[key].append (val)
336         except KeyError:
337                 warning (_ ("no such setting: %s") % `key`)
338                 dict[key] = [val]
339
340
341 def strip_extension (f, ext):
342         (p, e) = os.path.splitext (f)
343         if e == ext:
344                 e = ''
345         return p + e
346
347 # END Library
348
349 option_definitions = [
350         ('', 'd', 'dependencies', _ ("write Makefile dependencies for every input file")),
351         ('', 'h', 'help', _ ("this help")),
352         (_ ("DIR"), 'I', 'include', _ ("add DIR to LilyPond's search path")),
353         ('', 'k', 'keep', _ ("keep all output, and name the directory %s.dir") % program_name),
354         ('', '', 'no-lily', _ ("don't run LilyPond")),
355         ('', 'm', 'no-paper', _ ("produce MIDI output only")),
356         (_ ("FILE"), 'o', 'output', _ ("write ouput to FILE")),
357         (_ ("FILE"), 'f', 'find-pfa', _ ("find pfa fonts used in FILE")),
358         # why capital P?
359         ('', 'P', 'postscript', _ ("generate PostScript output")),
360         (_ ("KEY=VAL"), 's', 'set', _ ("change global setting KEY to VAL")),
361         ('', 'V', 'verbose', _ ("verbose")),
362         ('', 'v', 'version', _ ("print version number")),
363         ('', 'w', 'warranty', _ ("show warranty and copyright")),
364         ]
365
366 def run_lilypond (files, outbase, dep_prefix):
367         opts = ''
368 #       opts = opts + '--output=%s.tex' % outbase
369         opts = opts + ' ' + string.join (map (lambda x : '-I ' + x,
370                                               include_path))
371         if paper_p:
372                 opts = opts + ' ' + string.join (map (lambda x : '-H ' + x,
373                                                       fields))
374         else:
375                 opts = opts + ' --no-paper'
376                 
377         if track_dependencies_p:
378                 opts = opts + " --dependencies"
379                 if dep_prefix:
380                         opts = opts + ' --dep-prefix=%s' % dep_prefix
381
382         fs = string.join (files)
383
384         if not verbose_p:
385                 progress ( _("Running %s...") % 'LilyPond')
386                 # cmd = cmd + ' 1> /dev/null 2> /dev/null'
387         else:
388                 opts = opts + ' --verbose'
389         
390         system ('lilypond %s %s ' % (opts, fs))
391
392 def analyse_lilypond_output (filename, extra):
393         
394         # urg
395         '''Grep FILENAME for interesting stuff, and
396         put relevant info into EXTRA.'''
397         filename = filename+'.tex'
398         progress (_ ("Analyzing %s...") % filename)
399         s = open (filename).read ()
400
401         # search only the first 10k
402         s = s[:10240]
403         for x in ('textheight', 'linewidth', 'papersize', 'orientation'):
404                 m = re.search (r'\\def\\lilypondpaper%s{([^}]*)}'%x, s)
405                 if m:
406                         set_setting (extra, x, m.group (1))
407
408 def find_tex_files_for_base (base, extra):
409
410         """
411         Find the \header fields dumped from BASE.
412         """
413         
414         headerfiles = {}
415         for f in layout_fields:
416                 if os.path.exists (base + '.' + f):
417                         headerfiles[f] = base+'.'+f
418
419         if os.path.exists (base  +'.dep'):
420                 dependency_files.append (base + '.dep')
421
422         for f in extra_fields:
423                 if os.path.exists (base + '.' + f):
424                         extra[f].append (open (base + '.' + f).read ())
425         
426         return (base  +'.tex',headerfiles)
427          
428
429 def find_tex_files (files, extra):
430         """
431         Find all .tex files whose prefixes start with some name in FILES. 
432
433         """
434         
435         tfiles = []
436         
437         for f in files:
438                 x = 0
439                 while 1:
440                         fname = os.path.basename (f)
441                         fname = strip_extension (fname, '.ly')
442                         if x:
443                                 fname = fname + '-%d' % x
444
445                         if os.path.exists (fname + '.tex'):
446                                 tfiles.append (find_tex_files_for_base (fname, extra))
447                                 analyse_lilypond_output (fname, extra)
448                         else:
449                                 break
450
451                         x = x + 1
452         if not x:
453                 fstr = string.join (files, ', ')
454                 warning (_ ("no lilypond output found for %s") % fstr)
455         return tfiles
456
457 def one_latex_definition (defn, first):
458         s = '\n'
459         for (k,v) in defn[1].items ():
460                 val = open (v).read ()
461                 if (string.strip (val)):
462                         s = s + r'''\def\lilypond%s{%s}''' % (k, val)
463                 else:
464                         s = s + r'''\let\lilypond%s\relax''' % k
465                 s = s + '\n'
466
467         if first:
468                 s = s + '\\def\\mustmakelilypondtitle{}\n'
469         else:
470                 s = s + '\\def\\mustmakelilypondpiecetitle{}\n'
471                 
472         s = s + '\\input %s\n' % defn[0] # The final \n seems important here. It ensures that the footers and taglines end up on the right page.
473         return s
474
475
476 ly_paper_to_latexpaper =  {
477         'a4' : 'a4paper',
478         'letter' : 'letterpaper', 
479 }
480
481 def global_latex_definition (tfiles, extra):
482
483         '''construct preamble from EXTRA, dump Latex stuff for each
484 lily output file in TFILES after that, and return the Latex file constructed.  '''
485
486
487         s = ""
488         s = s + '% generation tag\n'
489
490         options = ''
491
492         if extra['papersize']:
493                 try:
494                         options = '%s' % ly_paper_to_latexpaper[extra['papersize'][0]]
495                 except KeyError:
496                         warning (_ ("invalid value: %s") % `extra['papersize'][0]`)
497                         pass
498
499         if extra['latexoptions']:
500                 options = options + ',' + extra['latexoptions'][-1]
501
502         s = s + '\\documentclass[%s]{article}\n' % options
503
504         if extra['language']:
505                 s = s + r'\usepackage[%s]{babel}\n' % extra['language'][-1]
506
507
508         s = s + '\\usepackage{%s}\n' \
509                 % string.join (extra['latexpackages'], ',')
510
511         if extra['latexheaders']:
512                 s = s + '\\include{%s}\n' \
513                         % string.join (extra['latexheaders'], '}\n\\include{')
514
515         textheight = ''
516         if extra['textheight']:
517                 textheight = ',textheight=%fpt' % extra['textheight'][0]
518
519         orientation = 'portrait'
520         if extra['orientation']:
521                 orientation = extra['orientation'][0]
522
523         # set sane geometry width (a4-width) for linewidth = -1.
524         maxlw = max (extra['linewidth'] + [-1])
525         if maxlw < 0:
526                 # who the hell is 597 ?
527                 linewidth = '597'
528         else:
529                 linewidth = maxlw
530         s = s + '\geometry{width=%spt%s,headheight=2mm,footskip=2mm,%s}\n' % (linewidth, textheight, orientation)
531
532         if extra['latexoptions']:
533                 s = s + '\geometry{twosideshift=4mm}\n'
534
535         s = s + r'''
536 \usepackage[latin1]{inputenc}
537 \input{titledefs}
538 '''
539         
540         if extra['pagenumber'] and extra['pagenumber'][-1] and extra['pagenumber'][-1] != 'no':
541                 s = s + '\setcounter{page}{%s}\n' % (extra['pagenumber'][-1])
542                 s = s + '\\pagestyle{plain}\n'
543         else:
544                 s = s + '\\pagestyle{empty}\n'
545
546         s = s + '\\begin{document}\n'
547         s = s + '\\thispagestyle{firstpage}\n'
548
549         first = 1
550         for t in tfiles:
551                 s = s + one_latex_definition (t, first)
552                 first = 0
553
554
555         s = s + '\\thispagestyle{lastpage}\n'
556         s = s + '\\end{document}'
557
558         return s
559
560 def run_latex (files, outbase, extra):
561
562         """Construct latex file, for FILES and EXTRA, dump it into
563 OUTBASE.latex. Run LaTeX on it.
564
565 RETURN VALUE
566
567 None
568         """
569         latex_fn = outbase + '.latex'
570         
571         wfs = find_tex_files (files, extra)
572         s = global_latex_definition (wfs, extra)
573
574         f = open (latex_fn, 'w')
575         f.write (s)
576         f.close ()
577
578         cmd = 'latex \\\\nonstopmode \\\\input %s' % latex_fn
579
580         if not verbose_p and os.name == 'posix':
581                 progress ( _("Running %s...") % 'LaTeX')
582                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
583
584         system (cmd)
585
586 def run_dvips (outbase, extra):
587
588
589         """Run dvips using the correct options taken from EXTRA,
590 leaving a PS file in OUTBASE.ps
591
592 RETURN VALUE
593
594 None.
595 """
596         opts = ''
597         if extra['papersize']:
598                 opts = opts + ' -t%s' % extra['papersize'][0]
599
600         if extra['orientation'] and extra['orientation'][0] == 'landscape':
601                 opts = opts + ' -tlandscape'
602
603         cmd = 'dvips %s -o%s %s' % (opts, outbase + '.ps', outbase + '.dvi')
604         
605         if not verbose_p and os.name == 'posix':
606                 progress ( _("Running %s...") % 'dvips')
607                 cmd = cmd + ' 1> /dev/null 2> /dev/null'
608                 
609         system (cmd)
610
611 def generate_dependency_file (depfile, outname):
612         df = open (depfile, 'w')
613         df.write (outname + ':' )
614         
615         for d in dependency_files:
616                 s = open (d).read ()
617                 s = re.sub ('#[^\n]*\n', '', s)
618                 s = re.sub (r'\\\n', ' ', s)
619                 m = re.search ('.*:(.*)\n', s)
620
621                 # ugh. Different targets?
622                 if m:
623                         df.write ( m.group (1)  + ' ' )
624
625         df.write ('\n')
626         df.close ();
627
628 def find_file_in_path (path, name):
629         for d in string.split (path, os.pathsep):
630                 if name in os.listdir (d):
631                         return os.path.join (d, name)
632
633 # Added as functionality to ly2dvi, because ly2dvi may well need to do this
634 # in future too.
635 PS = '%!PS-Adobe'
636 def find_pfa_fonts (name):
637         s = open (name).read ()
638         if s[:len (PS)] != PS:
639                 # no ps header?
640                 errorport.write (_( "error: ") + _ ("not a PostScript file: `%s\'" % name))
641                 errorport.write ('\n')
642                 sys.exit (1)
643         here = 0
644         m = re.match ('.*?/(feta[-a-z0-9]+) +findfont', s[here:], re.DOTALL)
645         pfa = []
646         while m:
647                 here = m.end (1)
648                 pfa.append (m.group (1))
649                 m = re.match ('.*?/(feta[-a-z0-9]+) +findfont', s[here:], re.DOTALL)
650         return pfa
651
652         
653 (sh, long) = getopt_args (__main__.option_definitions)
654 try:
655         (options, files) = getopt.getopt(sys.argv[1:], sh, long)
656 except getopt.error, s:
657         errorport.write ('\n')
658         errorport.write (_( "error: ") + _ ("getopt says: `%s\'" % s))
659         errorport.write ('\n')
660         errorport.write ('\n')
661         help ()
662         sys.exit (2)
663         
664 for opt in options:     
665         o = opt[0]
666         a = opt[1]
667
668         if 0:
669                 pass
670         elif o == '--help' or o == '-h':
671                 help ()
672                 sys.exit (0)
673         elif o == '--find-pfa' or o == '-f':
674                 fonts = map (lambda x: x + '.pfa', find_pfa_fonts (a))
675                 files = map (lambda x:
676                              find_file_in_path (os.environ['GS_FONTPATH'], x),
677                              fonts)
678                 print string.join (files, ' ')
679                 sys.exit (0)
680         elif o == '--include' or o == '-I':
681                 include_path.append (a)
682         elif o == '--postscript' or o == '-P':
683                 targets['PS'] = 0
684         elif o == '--keep' or o == '-k':
685                 keep_temp_dir_p = 1
686         elif o == '--no-lily':
687                 lily_p = 0
688         elif o == '--no-paper' or o == '-m':
689                 targets = {}
690                 targets['MIDI'] = 0
691                 paper_p = 0
692         elif o == '--output' or o == '-o':
693                 output_name = a
694         elif o == '--set' or o == '-s':
695                 ss = string.split (a, '=')
696                 set_setting (extra_init, ss[0], ss[1])
697         elif o == '--dependencies' or o == '-d':
698                 track_dependencies_p = 1
699         elif o == '--verbose' or o == '-V':
700                 verbose_p = 1
701         elif o == '--version' or o == '-v':
702                 identify ()
703                 sys.exit (0)
704         elif o == '--warranty' or o == '-w':
705                 status = system ('lilypond -w', ignore_error = 1)
706                 if status:
707                         warranty ()
708
709                 sys.exit (0)
710
711
712 def cp_to_dir (pattern, dir):
713         "Copy files matching re PATTERN from cwd to DIR"
714         # Duh.  Python style portable: cp *.EXT OUTDIR
715         # system ('cp *.%s %s' % (ext, outdir), 1)
716         files = filter (lambda x, p=pattern: re.match (p, x), os.listdir ('.'))
717         map (lambda x, d=dir: shutil.copy2 (x, os.path.join (d, x)), files)
718
719 # Python < 1.5.2 compatibility
720 #
721 # On most platforms, this is equivalent to
722 #`normpath(join(os.getcwd()), PATH)'.  *Added in Python version 1.5.2*
723 if os.path.__dict__.has_key ('abspath'):
724         abspath = os.path.abspath
725 else:
726         def abspath (path):
727                 return os.path.normpath (os.path.join (os.getcwd (), path))
728
729 if os.__dict__.has_key ('makedirs'):
730         makedirs = os.makedirs
731 else:
732         def makedirs (dir, mode=0777):
733                 system ('mkdir -p %s' % dir)
734
735 def mkdir_p (dir, mode=0777):
736         if not os.path.isdir (dir):
737                 makedirs (dir, mode)
738
739 include_path = map (abspath, include_path)
740
741 original_output = output_name
742
743
744 if files and files[0] != '-':
745
746         # Ugh, maybe make a setup () function
747         files = map (lambda x: strip_extension (x, '.ly'), files)
748
749         (outdir, outbase) = ('','')
750         if not output_name:
751                 outbase = os.path.basename (files[0])
752                 outdir = abspath('.')
753         elif output_name[-1] == os.sep:
754                 outdir = abspath (output_name)
755                 outbase = os.path.basename (files[0])
756         else:
757                 (outdir, outbase) = os.path.split (abspath (output_name))
758
759         for i in ('.dvi', '.latex', '.ly', '.ps', '.tex'):
760                 output_name = strip_extension (output_name, i)
761
762         files = map (abspath, files) 
763
764         if os.path.dirname (output_name) != '.':
765                 dep_prefix = os.path.dirname (output_name)
766         else:
767                 dep_prefix = 0
768
769         reldir = os.path.dirname (output_name)
770         if outdir != '.' and (track_dependencies_p or targets.keys ()):
771                 mkdir_p (outdir, 0777)
772
773         setup_environment ()
774         tmpdir = setup_temp ()
775         if cache_pks_p :
776                 os.chdir (outdir)
777                 cp_to_dir (PK_PATTERN, tmpdir)
778
779         os.chdir (tmpdir)
780         
781         if lily_p:
782                 try:
783                         run_lilypond (files, outbase, dep_prefix)
784                 except:
785                         # TODO: friendly message about LilyPond setup/failing?
786                         #
787                         # TODO: lilypond should fail with different
788                         # error codes for:
789                         #   - guile setup/startup failure
790                         #   - font setup failure
791                         #   - init.ly setup failure
792                         #   - parse error in .ly
793                         #   - unexpected: assert/core dump
794                         targets = {}
795                         traceback.print_exc ()
796
797         if targets.has_key ('DVI') or targets.has_key ('PS'):
798                 try:
799                         run_latex (files, outbase, extra_init)
800                         # unless: add --tex, or --latex?
801                         del targets['TEX']
802                         del targets['LATEX']
803                 except:
804                         # TODO: friendly message about TeX/LaTeX setup,
805                         # trying to run tex/latex by hand
806                         if targets.has_key ('DVI'):
807                                 del targets['DVI']
808                         if targets.has_key ('PS'):
809                                 del targets['PS']
810                         traceback.print_exc ()
811
812         if targets.has_key ('PS'):
813                 try:
814                         run_dvips (outbase, extra_init)
815                 except: 
816                         if targets.has_key ('PS'):
817                                 del targets['PS']
818                         traceback.print_exc ()
819
820         # add DEP to targets?
821         if track_dependencies_p:
822                 depfile = os.path.join (outdir, outbase + '.dep')
823                 generate_dependency_file (depfile, depfile)
824                 if os.path.isfile (depfile):
825                         progress (_ ("dependencies output to `%s'...") % depfile)
826
827         # Hmm, if this were a function, we could call it the except: clauses
828         for i in targets.keys ():
829                 ext = string.lower (i)
830                 cp_to_dir ('.*\.%s$' % ext, outdir)
831                 outname = outbase + '.' + string.lower (i)
832                 abs = os.path.join (outdir, outname)
833                 if reldir != '.':
834                         outname = os.path.join (reldir, outname)
835                 if os.path.isfile (abs):
836                         progress (_ ("%s output to `%s'...") % (i, outname))
837                 elif verbose_p:
838                         warning (_ ("can't find file: `%s'") % outname)
839                         
840                 if cache_pks_p:
841                         cp_to_dir (PK_PATTERN, outdir)
842                 
843         os.chdir (original_dir)
844         cleanup_temp ()
845         
846 else:
847         # FIXME: read from stdin when files[0] = '-'
848         help ()
849         errorport.write ("ly2dvi: " + _ ("error: ") + _ ("no files specified on command line.") + '\n')
850         sys.exit (2)
851
852
853