]> git.donarmstrong.com Git - lilypond.git/blob - python/lilylib.py
Lilylib: When formatting the options help, use only one level of indentation
[lilypond.git] / python / lilylib.py
1 # This file is part of LilyPond, the GNU music typesetter.
2 #
3 # Copyright (C) 1998--2010 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 def encoded_write(f, s):
51     f.write (s.encode (f.encoding or 'utf_8'))
52
53 # ugh, Python 2.5 optparse requires Unicode strings in some argument
54 # functions, and refuse them in some other places
55 def display_encode (s):
56     return s.encode (sys.stderr.encoding or 'utf_8')
57
58 # Lilylib globals.
59 program_version = '@TOPLEVEL_VERSION@'
60 program_name = os.path.basename (sys.argv[0])
61
62
63 # Check if program_version contains @ characters. This will be the case if
64 # the .py file is called directly while building the lilypond documentation.
65 # If so, try to check for the env var LILYPOND_VERSION, which is set by our
66 # makefiles and use its value.
67 at_re = re.compile (r'@')
68 if at_re.match (program_version):
69     if os.environ.has_key('LILYPOND_VERSION'):
70         program_version = os.environ['LILYPOND_VERSION']
71     else:
72         program_version = "unknown"
73
74 def stderr_write (s):
75     encoded_write (sys.stderr, s)
76
77 def warning (s):
78     stderr_write (program_name + ": " + _ ("warning: %s") % s + '\n')
79
80 def error (s):
81     stderr_write (program_name + ": " + _ ("error: %s") % s + '\n')
82
83 progress = stderr_write
84
85
86 def require_python_version ():
87     if sys.hexversion < 0x02040000:
88         stderr_write ("Python 2.4 or newer is required to run this program.\n\
89 Please upgrade Python from http://python.org/download/, and if you use MacOS X,\n\
90 please read 'Setup for MacOS X' in Application Usage.")
91         os.system ("open http://python.org/download/")
92         sys.exit (2)
93
94 # Modified version of the commands.mkarg(x), which always uses
95 # double quotes (since Windows can't handle the single quotes:
96 def mkarg(x):
97     s = ' "'
98     for c in x:
99         if c in '\\$"`':
100             s = s + '\\'
101         s = s + c
102     s = s + '"'
103     return s
104
105 def command_name (cmd):
106     # Strip all stuf after command,
107     # deal with "((latex ) >& 1 ) .." too
108     cmd = re.match ('([\(\)]*)([^\\\ ]*)', cmd).group (2)
109     return os.path.basename (cmd)
110
111 def subprocess_system (cmd,
112                        ignore_error=False,
113                        progress_p=True,
114                        be_verbose=False,
115                        log_file=None):
116     import subprocess
117
118     show_progress= progress_p
119     name = command_name (cmd)
120     error_log_file = ''
121
122     if be_verbose:
123         show_progress = 1
124         progress (_ ("Invoking `%s\'") % cmd)
125     else:
126         progress ( _("Running %s...") % name)
127
128
129     stdout_setting = None
130     if not show_progress:
131         stdout_setting = subprocess.PIPE
132
133     proc = subprocess.Popen (cmd,
134                              shell=True,
135                              universal_newlines=True,
136                              stdout=stdout_setting,
137                              stderr=stdout_setting)
138
139     log = ''
140
141     if show_progress:
142         retval = proc.wait()
143     else:
144         log = proc.communicate ()
145         retval = proc.returncode
146
147
148     if retval:
149         print >>sys.stderr, 'command failed:', cmd
150         if retval < 0:
151             print >>sys.stderr, "Child was terminated by signal", -retval
152         elif retval > 0:
153             print >>sys.stderr, "Child returned", retval
154
155         if ignore_error:
156             print >>sys.stderr, "Error ignored"
157         else:
158             if not show_progress:
159                 print log[0]
160                 print log[1]
161             sys.exit (1)
162
163     return abs (retval)
164
165 def ossystem_system (cmd,
166                      ignore_error=False,
167                      progress_p=True,
168                      be_verbose=False,
169                      log_file=None):
170
171
172     name = command_name (cmd)
173     if be_verbose:
174         show_progress = 1
175         progress (_ ("Invoking `%s\'") % cmd)
176     else:
177         progress ( _("Running %s...") % name)
178
179     retval = os.system (cmd)
180     if retval:
181         print >>sys.stderr, 'command failed:', cmd
182         if retval < 0:
183             print >>sys.stderr, "Child was terminated by signal", -retval
184         elif retval > 0:
185             print >>sys.stderr, "Child returned", retval
186
187         if ignore_error:
188             print >>sys.stderr, "Error ignored"
189         else:
190             sys.exit (1)
191
192     return abs (retval)
193
194
195 system = subprocess_system
196 if sys.platform == 'mingw32':
197
198     ## subprocess x-compile doesn't work.
199     system = ossystem_system
200
201 def strip_extension (f, ext):
202     (p, e) = os.path.splitext (f)
203     if e == ext:
204         e = ''
205     return p + e
206
207
208 def search_exe_path (name):
209     p = os.environ['PATH']
210     exe_paths = p.split (':')
211     for e in exe_paths:
212         full = os.path.join (e, name)
213         if os.path.exists (full):
214             return full
215     return None
216
217
218 def print_environment ():
219     for (k,v) in os.environ.items ():
220         sys.stderr.write ("%s=\"%s\"\n" % (k, v))
221
222 class NonDentedHeadingFormatter (optparse.IndentedHelpFormatter):
223     def format_heading(self, heading):
224         if heading:
225             return heading[0].upper() + heading[1:] + ':\n'
226         return ''
227     def format_option_strings(self, option):
228         sep = ' '
229         if option._short_opts and option._long_opts:
230             sep = ','
231
232         metavar = ''
233         if option.takes_value():
234             metavar = '=%s' % option.metavar or option.dest.upper()
235
236         return "%3s%s %s%s" % (" ".join (option._short_opts),
237                                sep,
238                                " ".join (option._long_opts),
239                                metavar)
240
241     # Only use one level of indentation (even for groups and nested groups),
242     # since we don't indent the headeings, either
243     def indent(self):
244         self.current_indent = self.indent_increment
245         self.level += 1
246     def dedent(self):
247         self.level -= 1
248         if self.level <= 0:
249             self.current_indent = ''
250             self.level = 0;
251
252     def format_usage(self, usage):
253         return _("Usage: %s") % usage + '\n'
254
255     def format_description(self, description):
256         return description
257
258 def get_option_parser (*args, **kwargs):
259     p = optparse.OptionParser (*args, **kwargs)
260     p.formatter = NonDentedHeadingFormatter ()
261     return p