Revert "Fix percent-escape URI issue (hopefully)."
[lilypad-macos.git] / lilycall.py
blob5c2e6b8dffd297da75616ca34915e32e93e73574
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
32 return writable
34 def quote_quotes (str):
35 return re.sub ('"', '\\"', str)
38 ################################################################
39 # lily call utils
41 def check_fontconfig (appdir):
42 prefix = appdir + '/Contents/Resources'
43 my_sysfont_dir = prefix + '/share/SystemFonts'
44 sysfont_dir = '/System/Library/Fonts'
46 fc_cache = (prefix + '/font.cache-1')
47 local_fc_conf = open (prefix + '/etc/fonts/local.conf','w')
48 local_fc_conf.write ('''<?xml version="1.0"?>
49 <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
50 <!-- /etc/fonts/local.conf file for local customizations -->
51 <fontconfig>
52 <dir>%s</dir>
53 <cache>%s</cache>
54 </fontconfig>''' % (appdir + '/Contents/Resources/share/fonts/', fc_cache))
56 need_update = not os.path.exists (fc_cache)
57 if need_update:
58 open (fc_cache, 'w').write ('')
59 return need_update
61 def get_env (prefix):
62 p = ''
63 try:
64 p = os.environ['DYLD_LIBRARY_PATH']
65 except KeyError:
66 pass
68 env = {}
70 # need this for GUILE
71 env['DYLD_LIBRARY_PATH'] = prefix + '/lib' + ':' + p
72 env['FONTCONFIG_PATH'] = prefix + '/etc/fonts/'
73 env['GS_LIB'] = prefix + '/share/ghostscript/8.15/lib/'
74 env['GUILE_LOAD_PATH'] = prefix + '/share/guile/1.6'
75 env['LILYPOND_DATADIR'] = prefix + '/share/lilypond/current'
76 env['PANGO_RC_FILE'] = prefix + '/etc/pango/pangorc'
77 env['HOME'] = os.environ['HOME']
78 env['PATH'] = prefix + '/bin/' + ':' + os.environ['PATH']
79 env['PANGO_PREFIX'] = prefix
80 return env
83 def get_gui_command_line (appdir, args):
84 new_args = ['']
86 cwd = os.getcwd ()
87 for a in args:
88 if a[0] not in ['-','/']:
89 a = os.path.join (cwd, a)
90 new_args.append (a)
91 return new_args
93 def get_dest_dir (arguments):
94 try:
95 dest_dir = os.environ['LILYPOND_DESTDIR']
96 except KeyError:
97 dest_dir = ''
99 for a in arguments:
100 if (not dest_dir and a and a[0] == '/'):
101 dest_dir = os.path.split (a)[0]
102 break
104 if not dest_dir or not writable_directory (dest_dir):
105 dest_dir = os.environ['HOME']+ '/Desktop'
107 return dest_dir
109 ################################################################
110 # the class
112 class Call:
113 def check_app_dir (self, dir):
114 self.error_string = ''
115 if not writable_directory (dir):
116 self.error_string = ('Cannot write program directory\n'
117 + 'This program must be installed before using.')
119 elif dir[0] <> '/':
120 self.error_string = ("Application directory should be absolute. "
121 + "Was: %s\n"
122 % dir)
124 def __init__ (self, appdir, args):
125 self.check_app_dir (appdir)
126 if self.error_string:
127 return
129 self.appdir = appdir
130 self.env = get_env (appdir + '/Contents/Resources')
131 self.executable = appdir + '/Contents/Resources/bin/lilypond'
132 self.args = [self.executable] + args
133 self.cwd = '.'
135 self.need_fc_update = check_fontconfig (appdir)
136 self.reroute_output = False
138 def set_gui_options (self):
139 self.args = ([self.args[0]]
140 + get_gui_command_line (self.appdir, self.args[1:]))
142 self.cwd = get_dest_dir (self.args[1:])
143 self.reroute_output = 1
145 def print_env (self):
146 for (k,v) in self.env.items ():
147 print 'export %s="%s"' % (k,v)
149 def get_process (self, executable, args):
150 out = None
151 err = None
152 if self.reroute_output:
153 out = subprocess.PIPE
154 err = subprocess.STDOUT
156 if debug:
157 self.print_env ()
158 print 'args: ', args
159 print 'executable: ', executable
161 self.args[0] = os.path.split (self.args[0])[1]
162 process = subprocess.Popen (args,
163 executable = executable,
164 cwd = self.cwd,
165 env = self.env,
166 stdout = out,
167 stderr = err,
168 shell = False)
170 return process
172 def get_lilypond_process (self):
173 return self.get_process (self.executable, self.args)
175 def get_pdfs (self):
176 names = []
177 for a in self.args:
178 pdf = os.path.splitext (a)[0] + '.pdf'
179 if os.path.exists (pdf):
180 names.append (pdf)
182 return names
184 # data - for callbacks.
185 def open_pdfs (self, data = None):
186 pdfs = self.get_pdfs ()
187 if pdfs:
188 b = '/usr/bin/open'
189 args = [b] + pdfs
190 if debug:
191 print 'invoking ', args
192 os.spawnv (os.P_NOWAIT, b, [b] + pdfs)
194 ################################################################
195 # default: wrap a LP call, open PDFs.
197 if __name__ == '__main__':
198 invocation = sys.argv[0]
199 appdir_dir = sys.argv[1]
201 argv = sys.argv[2:]
203 if '--debug' in argv:
204 debug = 1
205 argv.remove ('--debug')
207 call = Call (appdir_dir, argv)
209 if call.error_string:
210 sys.stderr.write (call.error_string)
211 sys.exit (2)
213 if call.need_fc_update:
214 sys.stderr.write ('Rebuilding font cache\nThis may take a few minutes.')
216 p = call.get_lilypond_process ()
217 code = p.wait ()
219 if not sys.stdin.isatty (): # GUI
220 call.open_pdfs ()
222 sys.exit (code)