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