]> git.donarmstrong.com Git - lilypond.git/blob - python/lilylib.py
Imported Upstream version 2.14.2
[lilypond.git] / python / lilylib.py
1 # This file is part of LilyPond, the GNU music typesetter.
2 #
3 # Copyright (C) 1998--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
4 #                Jan Nieuwenhuizen <janneke@gnu.org>
5 #
6 # LilyPond is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # LilyPond is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18
19 import __main__
20 import glob
21 import os
22 import re
23 import shutil
24 import sys
25 import optparse
26
27 ################################################################
28 # Users of python modules should include this snippet
29 # and customize variables below.
30
31
32 # Python 2.5 only accepts strings with proper Python internal encoding
33 # (i.e. ASCII or Unicode) when writing to stdout/stderr, so we must
34 # use ugettext iso gettext, and encode the string when writing to
35 # stdout/stderr
36
37 localedir = '@localedir@'
38 try:
39     import gettext
40     t = gettext.translation ('lilypond', localedir)
41     _ = t.ugettext
42 except:
43     def _ (s):
44         return s
45 underscore = _
46
47 # Urg, Python 2.4 does not define stderr/stdout encoding
48 # Maybe guess encoding from LANG/LC_ALL/LC_CTYPE?
49
50 reload (sys)
51 sys.setdefaultencoding ('utf-8')
52 import codecs
53 sys.stdout = codecs.getwriter ('utf8') (sys.stdout)
54 sys.stderr = codecs.getwriter ('utf8') (sys.stderr)
55
56 def encoded_write(f, s):
57     f.write (s.encode (f.encoding or 'utf-8', 'replace'))
58
59 # ugh, Python 2.5 optparse requires Unicode strings in some argument
60 # functions, and refuse them in some other places
61 def display_encode (s):
62     return s.encode (sys.stderr.encoding or 'utf-8', 'replace')
63
64 # Lilylib globals.
65 program_version = '@TOPLEVEL_VERSION@'
66 program_name = os.path.basename (sys.argv[0])
67
68
69 # Check if program_version contains @ characters. This will be the case if
70 # the .py file is called directly while building the lilypond documentation.
71 # If so, try to check for the env var LILYPOND_VERSION, which is set by our
72 # makefiles and use its value.
73 at_re = re.compile (r'@')
74 if at_re.match (program_version):
75     if os.environ.has_key('LILYPOND_VERSION'):
76         program_version = os.environ['LILYPOND_VERSION']
77     else:
78         program_version = "unknown"
79
80 def stderr_write (s):
81     encoded_write (sys.stderr, s)
82
83 def warning (s):
84     stderr_write (program_name + ": " + _ ("warning: %s") % s + '\n')
85
86 def error (s):
87     stderr_write (program_name + ": " + _ ("error: %s") % s + '\n')
88
89 progress = stderr_write
90
91
92 def require_python_version ():
93     if sys.hexversion < 0x02040000:
94         stderr_write ("Python 2.4 or newer is required to run this program.\n\
95 Please upgrade Python from http://python.org/download/, and if you use MacOS X,\n\
96 please read 'Setup for MacOS X' in Application Usage.")
97         os.system ("open http://python.org/download/")
98         sys.exit (2)
99
100 # Modified version of the commands.mkarg(x), which always uses
101 # double quotes (since Windows can't handle the single quotes:
102 def mkarg(x):
103     s = ' "'
104     for c in x:
105         if c in '\\$"`':
106             s = s + '\\'
107         s = s + c
108     s = s + '"'
109     return s
110
111 def command_name (cmd):
112     # Strip all stuf after command,
113     # deal with "((latex ) >& 1 ) .." too
114     cmd = re.match ('([\(\)]*)([^\\\ ]*)', cmd).group (2)
115     return os.path.basename (cmd)
116
117 def subprocess_system (cmd,
118                        ignore_error=False,
119                        progress_p=True,
120                        be_verbose=False,
121                        log_file=None):
122     import subprocess
123
124     show_progress= progress_p
125     name = command_name (cmd)
126     error_log_file = ''
127
128     if be_verbose:
129         show_progress = 1
130         progress (_ ("Invoking `%s\'") % cmd)
131     else:
132         progress ( _("Running %s...") % name)
133
134
135     stdout_setting = None
136     if not show_progress:
137         stdout_setting = subprocess.PIPE
138
139     proc = subprocess.Popen (cmd,
140                              shell=True,
141                              universal_newlines=True,
142                              stdout=stdout_setting,
143                              stderr=stdout_setting)
144
145     log = ''
146
147     if show_progress:
148         retval = proc.wait()
149     else:
150         log = proc.communicate ()
151         retval = proc.returncode
152
153
154     if retval:
155         print >>sys.stderr, 'command failed:', cmd
156         if retval < 0:
157             print >>sys.stderr, "Child was terminated by signal", -retval
158         elif retval > 0:
159             print >>sys.stderr, "Child returned", retval
160
161         if ignore_error:
162             print >>sys.stderr, "Error ignored"
163         else:
164             if not show_progress:
165                 print log[0]
166                 print log[1]
167             sys.exit (1)
168
169     return abs (retval)
170
171 def ossystem_system (cmd,
172                      ignore_error=False,
173                      progress_p=True,
174                      be_verbose=False,
175                      log_file=None):
176
177
178     name = command_name (cmd)
179     if be_verbose:
180         show_progress = 1
181         progress (_ ("Invoking `%s\'") % cmd)
182     else:
183         progress ( _("Running %s...") % name)
184
185     retval = os.system (cmd)
186     if retval:
187         print >>sys.stderr, 'command failed:', cmd
188         if retval < 0:
189             print >>sys.stderr, "Child was terminated by signal", -retval
190         elif retval > 0:
191             print >>sys.stderr, "Child returned", retval
192
193         if ignore_error:
194             print >>sys.stderr, "Error ignored"
195         else:
196             sys.exit (1)
197
198     return abs (retval)
199
200
201 system = subprocess_system
202 if sys.platform == 'mingw32':
203
204     ## subprocess x-compile doesn't work.
205     system = ossystem_system
206
207 def strip_extension (f, ext):
208     (p, e) = os.path.splitext (f)
209     if e == ext:
210         e = ''
211     return p + e
212
213
214 def search_exe_path (name):
215     p = os.environ['PATH']
216     exe_paths = p.split (':')
217     for e in exe_paths:
218         full = os.path.join (e, name)
219         if os.path.exists (full):
220             return full
221     return None
222
223
224 def print_environment ():
225     for (k,v) in os.environ.items ():
226         sys.stderr.write ("%s=\"%s\"\n" % (k, v))
227
228 class NonDentedHeadingFormatter (optparse.IndentedHelpFormatter):
229     def format_heading(self, heading):
230         if heading:
231             return heading[0].upper() + heading[1:] + ':\n'
232         return ''
233     def format_option_strings(self, option):
234         sep = ' '
235         if option._short_opts and option._long_opts:
236             sep = ','
237
238         metavar = ''
239         if option.takes_value():
240             metavar = '=%s' % option.metavar or option.dest.upper()
241
242         return "%3s%s %s%s" % (" ".join (option._short_opts),
243                                sep,
244                                " ".join (option._long_opts),
245                                metavar)
246
247     # Only use one level of indentation (even for groups and nested groups),
248     # since we don't indent the headeings, either
249     def indent(self):
250         self.current_indent = self.indent_increment
251         self.level += 1
252     def dedent(self):
253         self.level -= 1
254         if self.level <= 0:
255             self.current_indent = ''
256             self.level = 0;
257
258     def format_usage(self, usage):
259         return _("Usage: %s") % usage + '\n'
260
261     def format_description(self, description):
262         return description
263
264 def get_option_parser (*args, **kwargs):
265     p = optparse.OptionParser (*args, **kwargs)
266     p.formatter = NonDentedHeadingFormatter ()
267     p.formatter.set_parser (p)
268     return p