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