LILYPONDPREFIX -> LILYPOND_DATADIR
[lilypad-macos.git] / lilycall.py
blobeee483b4d89aa52449e7317e756d89ddd7cc0ac8
1 #!/usr/bin/python
4 # Pythonic interface to LilyPond call.
8 import os
9 import sys
10 import string
11 import re
12 import subprocess
14 debug = 0
16 ################################################################
17 # general utils
19 def file_is_newer (f1, f2):
20 return os.stat (f1).st_mtime > os.stat (f2).st_mtime
22 def writable_directory (dir):
23 writable = 0
24 try:
25 testfile = os.path.join (dir,".testwrite")
26 f = open (testfile, 'w')
27 f.close()
28 writable = 1
29 os.unlink (testfile)
30 except IOError:
31 pass
33 return writable
36 def quote_quotes (str):
37 return re.sub ('"', '\\"', str)
40 ################################################################
41 # lily call utils
43 def check_fontconfig (appdir):
44 prefix = appdir + '/Contents/Resources'
45 my_sysfont_dir = prefix + '/share/SystemFonts'
46 sysfont_dir = '/System/Library/Fonts'
48 fc_cache = (prefix + '/font.cache-1')
49 local_fc_conf = open (prefix + '/etc/fonts/local.conf','w')
50 local_fc_conf.write ('''<?xml version="1.0"?>
51 <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
52 <!-- /etc/fonts/local.conf file for local customizations -->
53 <fontconfig>
54 <dir>%s</dir>
55 <cache>%s</cache>
56 </fontconfig>''' % (appdir + '/Contents/Resources/share/fonts/', fc_cache))
58 need_update = not os.path.exists (fc_cache)
59 if need_update:
60 open (fc_cache, 'w').write ('')
62 return need_update
64 def get_env (prefix):
65 p = ''
66 try:
67 p = os.environ['DYLD_LIBRARY_PATH']
68 except KeyError:
69 pass
71 env = {}
74 # need this for GUILE
75 env['DYLD_LIBRARY_PATH'] = prefix + '/lib' + ':' + p
76 env['FONTCONFIG_PATH'] = prefix + '/etc/fonts/'
77 env['GS_LIB'] = prefix + '/share/ghostscript/8.15/lib/'
78 env['GUILE_LOAD_PATH'] = prefix + '/share/guile/1.6'
79 env['LILYPOND_DATADIR'] = prefix + '/share/lilypond/current'
80 env['PANGO_RC_FILE'] = prefix + '/etc/pango/pangorc'
81 env['HOME'] = os.environ['HOME']
82 env['PATH'] = prefix + '/bin/' + ':' + os.environ['PATH']
83 env['PANGO_PREFIX'] = prefix
84 return env
87 def get_gui_command_line (appdir, args):
88 new_args = ['']
90 cwd = os.getcwd ()
91 for a in args:
92 if a[0] not in ['-','/']:
93 a = os.path.join (cwd, a)
94 new_args.append (a)
96 return new_args
98 def get_dest_dir (arguments):
99 try:
100 dest_dir = os.environ['LILYPOND_DESTDIR']
101 except KeyError:
102 dest_dir = ''
104 for a in arguments:
105 if (not dest_dir
106 and a and a[0] == '/'):
107 dest_dir = os.path.split (a)[0]
108 break
110 if not dest_dir or not writable_directory (dest_dir):
111 dest_dir = os.environ['HOME']+ '/Desktop'
113 return dest_dir
115 ################################################################
116 # the class
118 class Call:
119 def check_app_dir (self, dir):
120 self.error_string = ''
121 if not writable_directory (dir):
122 self.error_string = ('Cannot write program directory\n'
123 +'This program must be installed before using.')
125 elif dir[0] <> '/':
126 self.error_string = ("Application directory should be absolute. "
127 + "Was: %s\n"
128 % dir)
130 def __init__ (self, appdir, args):
131 self.check_app_dir (appdir)
132 if self.error_string:
133 return
135 self.appdir = appdir
136 self.env = get_env (appdir + '/Contents/Resources')
137 self.executable = appdir + '/Contents/Resources/bin/lilypond'
138 self.args = [self.executable] + args
139 self.cwd = '.'
141 self.need_fc_update = check_fontconfig (appdir)
142 self.reroute_output = False
144 def set_gui_options (self):
145 self.args = ([self.args[0]]
146 + get_gui_command_line (self.appdir, self.args[1:]))
148 self.cwd = get_dest_dir (self.args[1:])
149 self.reroute_output = 1
151 def print_env (self):
152 for (k,v) in self.env.items ():
153 print 'export %s="%s"' % (k,v)
155 def get_process (self, executable, args):
156 out = None
157 err = None
158 if self.reroute_output:
159 out = subprocess.PIPE
160 err = subprocess.STDOUT
162 if debug:
163 self.print_env ()
164 print 'args: ', args
165 print 'executable: ', executable
167 self.args[0] = os.path.split (self.args[0])[1]
168 process = subprocess.Popen (args,
169 executable = executable,
170 cwd = self.cwd,
171 env = self.env,
172 stdout = out,
173 stderr = err,
174 shell = False)
176 return process
178 def get_lilypond_process (self):
179 return self.get_process (self.executable, self.args)
181 def get_pdfs (self):
182 names = []
183 for a in self.args:
184 pdf = os.path.splitext (a)[0] + '.pdf'
185 if os.path.exists (pdf):
186 names.append (pdf)
188 return names
190 # data - for callbacks.
191 def open_pdfs (self, data = None):
192 pdfs = self.get_pdfs ()
193 if pdfs:
194 b = '/usr/bin/open'
195 args = [b] + pdfs
196 if debug:
197 print 'invoking ', args
198 os.spawnv (os.P_NOWAIT, b, [b] + pdfs)
200 ################################################################
201 # default: wrap a LP call, open PDFs.
203 if __name__ == '__main__':
204 invocation = sys.argv[0]
205 appdir_dir = sys.argv[1]
207 argv = sys.argv[2:]
209 if '--debug' in argv:
210 debug = 1
211 argv.remove ('--debug')
213 call = Call(appdir_dir, argv)
215 if call.error_string:
216 sys.stderr.write (call.error_string)
217 sys.exit (2)
219 if call.need_fc_update:
220 sys.stderr.write ('Rebuilding font cache\nThis may take a few minutes.')
222 p = call.get_lilypond_process ()
223 code = p.wait ()
225 if not sys.stdin.isatty (): # GUI
226 call.open_pdfs ()
228 sys.exit (code)