#
# source file of the GNU LilyPond music typesetter
#
-# (c) 1998--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+# (c) 1998--2006 Han-Wen Nienhuys <hanwen@cs.uu.nl>
# Jan Nieuwenhuizen <janneke@gnu.org>
### subst:\(^\|[^._a-z]\)\(abspath\|identify\|warranty\|progress\|warning\|error\|exit\|getopt_args\|option_help_str\|options_help_str\|help\|setup_temp\|read_pipe\|system\|cleanup_temp\|strip_extension\|cp_to_dir\|mkdir_p\|init\) *(
### subst: \(help_summary\|keep_temp_dir_p\|option_definitions\|original_dir\|program_name\|pseudo_filter_p\|temp_dir\|verbose_p\)
import __main__
+import getopt
+import glob
+import os
+import re
import shutil
import string
import sys
import tempfile
+import optparse
################################################################
# Users of python modules should include this snippet
# If set, LILYPONDPREFIX must take prevalence
# if datadir is not set, we're doing a build and LILYPONDPREFIX
-import getopt, os, sys
+
datadir = '@local_lilypond_datadir@'
if not os.path.isdir (datadir):
datadir = '@lilypond_datadir@'
sys.path.insert (0, os.path.join (datadir, 'python'))
-# Customize these
-if __name__ == '__main__':
- import lilylib as ly
- global _;_=ly._
- global re;re = ly.re
-
- # lilylib globals
- program_name = 'unset'
- pseudo_filter_p = 0
- original_dir = os.getcwd ()
- temp_dir = os.path.join (original_dir, '%s.dir' % program_name)
- keep_temp_dir_p = 0
- verbose_p = 0
-
- help_summary = _ ("lilylib module")
-
- option_definitions = [
- ('', 'h', 'help', _ ("this help")),
- ]
- from lilylib import *
-################################################################
-
-# Handle bug in Python 1.6-2.1
-#
-# there are recursion limits for some patterns in Python 1.6 til 2.1.
-# fix this by importing pre instead. Fix by Mats.
-if float (sys.version[0:3]) <= 2.1:
- try:
- import pre
- re = pre
- del pre
- except ImportError:
- import re
-else:
- import re
-
-# Attempt to fix problems with limited stack size set by Python!
-# Sets unlimited stack size. Note that the resource module only
-# is available on UNIX.
-try:
- import resource
- resource.setrlimit (resource.RLIMIT_STACK, (-1, -1))
-except:
- pass
+localedir = '@localedir@'
try:
import gettext
gettext.bindtextdomain ('lilypond', localedir)
return s
underscore = _
-program_version = '@TOPLEVEL_VERSION@'
-if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
- program_version = '1.7.5'
-
def identify (port):
- port.write ('%s (GNU LilyPond) %s\n' % (__main__.program_name, program_version))
+ port.write ('%s (GNU LilyPond) %s\n' % (__main__.program_name, __main__.program_version))
def warranty ():
identify (sys.stdout)
sys.stdout.write ('\n')
- sys.stdout.write (_ ('Copyright (c) %s by' % ' 1998--2002'))
+ sys.stdout.write (_ ("Copyright (c) %s by") % '1998--2006')
sys.stdout.write ('\n')
map (lambda x: sys.stdout.write (' %s\n' % x), __main__.copyright)
sys.stdout.write ('\n')
sys.stderr.write (s)
def warning (s):
- sys.stderr.write (__main__.program_name + ":" + _ ("warning: ") + s + '\n')
+ sys.stderr.write (__main__.program_name + ": " + _ ("warning: %s") % s + '\n')
def error (s):
- sys.stderr.write (__main__.program_name + ":" + _ ("error: ") + s + '\n')
+ sys.stderr.write (__main__.program_name + ": " + _ ("error: %s") % s + '\n')
def exit (i):
- if __main__.verbose_p:
+ be_verbose = get_global_option('verbose_p', 'verbose')
+ if be_verbose:
raise _ ('Exiting (%d)...') % i
else:
- sys.exit (1)
+ sys.exit (i)
def getopt_args (opts):
'''Construct arguments (LONG, SHORT) for getopt from list of options.'''
return (short, long)
def option_help_str (o):
- '''Transform one option description (4-tuple ) into neatly formatted string'''
+ '''Transform one option description (4-tuple) into neatly formatted string'''
sh = ' '
if o[1]:
sh = '-%s' % o[1]
- sep = ' '
+ sep = ' '
if o[1] and o[2]:
- sep = ','
+ sep = ', '
long = ''
if o[2]:
str = ''
for s in strs:
- str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0]) + 3), s[1])
+ first = 1
+ for ss in re.split ('\n\s*', s[1]):
+ if first:
+ str = str + '%s%s%s\n' \
+ % (s[0], ' ' * (w - len (s[0]) + 3), ss)
+ first = 0
+ else:
+ str = str + '%s%s\n' \
+ % (' ' * (w + 3), ss)
return str
def help ():
- ls = [(_ ("Usage: %s [OPTION]... FILE") % __main__.program_name),
+ ls = [(_ ("Usage: %s [OPTIONS]... FILE") % __main__.program_name),
('\n\n'),
(__main__.help_summary),
('\n\n'),
('\n'),
(options_help_str (__main__.option_definitions)),
('\n\n'),
- (_ ("Report bugs to %s") % 'bug-lilypond@gnu.org'),
+ (_ ("Report bugs to %s.") % 'bug-lilypond@gnu.org'),
('\n')]
map (sys.stdout.write, ls)
+
+def lilypond_version (binary):
+ p = read_pipe ('%s --version ' % binary)
+
+ ls = p.split ('\n')
+ v= '<not found>'
+ for l in ls:
+ m = re.search ('GNU LilyPond ([0-9a-z.]+)', p)
+ if m:
+ v = m.group (1)
+
+ return v
+
+def lilypond_version_check (binary, req):
+ if req[0] <> '@' :
+ v = lilypond_version (binary)
+ if v <> req:
+ error (_("Binary %s has version %s, looking for version %s") % \
+ (binary, v, req))
+ sys.exit (1)
+
def setup_temp ():
if not __main__.keep_temp_dir_p:
__main__.temp_dir = tempfile.mktemp (__main__.program_name)
try:
- os.mkdir (__main__.temp_dir, 0777)
+ os.mkdir (__main__.temp_dir, 0700)
except OSError:
pass
return __main__.temp_dir
def command_name (cmd):
- return re.match ('^[ \t]*([^ \t]*)', cmd).group (1)
+ # Strip all stuf after command,
+ # deal with "((latex ) >& 1 ) .." too
+ cmd = re.match ('([\(\)]*)([^\\\ ]*)', cmd).group (2)
+ return os.path.basename (cmd)
def error_log (name):
- return os.path.join (__main__.temp_dir, '%s.errorlog' % name)
+ name = re.sub('[^a-z]','x', name)
+ return tempfile.mktemp ('%s.errorlog' % name)
def read_pipe (cmd, mode = 'r'):
+
+
redirect = ''
- if __main__.verbose_p:
+ error_log_file = ''
+ if be_verbose:
progress (_ ("Opening pipe `%s\'") % cmd)
- redirect = ' 2>%s' % error_log (command_name (cmd))
+ else:
+ error_log_file = error_log (command_name (cmd))
+ redirect = ' 2>%s' % error_log_file
+
pipe = os.popen (cmd + redirect, mode)
output = pipe.read ()
status = pipe.close ()
if status:
error (_ ("`%s\' failed (%d)") % (cmd, exit_status))
- if not __main__.verbose_p:
- error (_ ("The error log is as follows:"))
- sys.stderr.write (open (error_log (command_name (cmd)).read ()))
- exit (status)
- if __main__.verbose_p:
+
+ if not be_verbose:
+ contents = open (error_log_file).read ()
+ if contents:
+ error (_ ("The error log is as follows:"))
+ sys.stderr.write (contents)
+
+ # Ugh. code dup
+ if error_log_file:
+ os.unlink (error_log_file)
+
+ exit (1)
+
+ if be_verbose:
progress ('\n')
+
+ if error_log_file:
+ os.unlink (error_log_file)
+
return output
+def get_global_option (old, new):
+ try:
+ return __main__.__dict__[old]
+ except KeyError:
+ return __main__.global_options.__dict__[new]
+
def system (cmd, ignore_error = 0, progress_p = 0):
'''System CMD. If IGNORE_ERROR, do not complain when CMD
Exit status of CMD '''
name = command_name (cmd)
+ error_log_file = ''
- if __main__.verbose_p:
+ ## UGH
+ be_verbose = get_global_option('verbose_p', 'verbose')
+ pseudo_filter = get_global_option ('pseudo_filter_p', 'pseudo_filter')
+
+ if be_verbose:
progress_p = 1
progress (_ ("Invoking `%s\'") % cmd)
else:
redirect = ''
if not progress_p:
- redirect = ' 1>/dev/null 2>' + error_log (name)
- elif __main__.pseudo_filter_p:
+ error_log_file = error_log (name)
+ redirect = ' 1>/dev/null 2>' + error_log_file
+ elif pseudo_filter:
redirect = ' 1>/dev/null'
-
+
status = os.system (cmd + redirect)
signal = 0x0f & status
exit_status = status >> 8
if status:
- msg = _ ("`%s\' failed (%d)") % (name, exit_status)
+
+ exit_type = 'status %d' % exit_status
+ if signal:
+ exit_type = 'signal %d' % signal
+
+ msg = _ ("`%s\' failed (%s)") % (name, exit_type)
if ignore_error:
- if __main__.verbose_p:
+ if be_verbose:
warning (msg + ' ' + _ ("(ignored)"))
else:
error (msg)
- if not progress_p:
+ if not progress_p and error_log_file:
error (_ ("The error log is as follows:"))
- sys.stderr.write (open (error_log (name)).read ())
- exit (status)
+ sys.stderr.write (open (error_log_file).read ())
+ if error_log_file:
+ os.unlink (error_log_file)
+ exit (1)
+ if error_log_file:
+ os.unlink (error_log_file)
progress ('\n')
return status
def cleanup_temp ():
+ be_verbose = get_global_option('verbose_p', 'verbose')
if not __main__.keep_temp_dir_p:
- if __main__.verbose_p:
+ if be_verbose:
progress (_ ("Cleaning %s...") % __main__.temp_dir)
shutil.rmtree (__main__.temp_dir)
- if __main__.verbose_p:
+ if be_verbose:
progress ('\n')
def cp_to_dir (pattern, dir):
"Copy files matching re PATTERN from cwd to DIR"
+
# Duh. Python style portable: cp *.EXT OUTDIR
# system ('cp *.%s %s' % (ext, outdir), 1)
+
files = filter (lambda x, p=pattern: re.match (p, x), os.listdir ('.'))
map (lambda x, d=dir: shutil.copy2 (x, os.path.join (d, x)), files)
-# Python < 1.5.2 compatibility
-#
-# On most platforms, this is equivalent to
-#`normpath(join(os.getcwd()), PATH)'. *Added in Python version 1.5.2*
-if os.path.__dict__.has_key ('abspath'):
- abspath = os.path.abspath
-else:
- def abspath (path):
- return os.path.normpath (os.path.join (os.getcwd (), path))
-
-if os.__dict__.has_key ('makedirs'):
- makedirs = os.makedirs
-else:
- def makedirs (dir, mode=0777):
- system ('mkdir -p %s' % dir)
+def search_exe_path (name):
+ p = os.environ['PATH']
+ exe_paths = string.split (p, ':')
+ for e in exe_paths:
+ full = os.path.join (e, name)
+ if os.path.exists (full):
+ return full
+ return None
def mkdir_p (dir, mode=0777):
if not os.path.isdir (dir):
makedirs (dir, mode)
-
-environment = {}
-
-# tex needs lots of memory, more than it gets by default on Debian
-non_path_environment = {
- 'extra_mem_top' : '1000000',
- 'extra_mem_bottom' : '1000000',
- 'pool_size' : '250000',
-}
-
-def setup_environment ():
- global environment
-
- kpse = read_pipe ('kpsexpand \$TEXMF')
- texmf = re.sub ('[ \t\n]+$','', kpse)
- type1_paths = read_pipe ('kpsewhich -expand-path=\$T1FONTS')
-
- environment = {
- # TODO: * prevent multiple addition.
- # * clean TEXINPUTS, MFINPUTS, TFMFONTS,
- # as these take prevalence over $TEXMF
- # and thus may break tex run?
- 'TEXMF' : "{%s,%s}" % (datadir, texmf) ,
- 'GS_FONTPATH' : type1_paths,
- 'GS_LIB' : datadir + '/ps',
- }
-
- # $TEXMF is special, previous value is already taken care of
- if os.environ.has_key ('TEXMF'):
- del os.environ['TEXMF']
-
- for key in environment.keys ():
- val = environment[key]
- if os.environ.has_key (key):
- val = os.environ[key] + os.pathsep + val
- os.environ[key] = val
-
- for key in non_path_environment.keys ():
- val = non_path_environment[key]
- os.environ[key] = val
-
def print_environment ():
for (k,v) in os.environ.items ():
sys.stderr.write ("%s=\"%s\"\n" % (k, v))
-def get_bbox (filename):
- ####system ('gs -sDEVICE=bbox -q -sOutputFile=- -dNOPAUSE %s -c quit > %s.bbox 2>&1 ' % (filename, filename))
- #### FIXME: 2>&1 ? --jcn
- bbox = filename + '.bbox'
- ## -sOutputFile does not work with bbox?
- ##cmd = 'gs -sDEVICE=bbox -q -sOutputFile=%s -dNOPAUSE %s -c quit' % \
- ## (bbox, filename)
- cmd = 'gs -sDEVICE=bbox -q -dNOPAUSE %s -c quit 2>%s' % \
- (filename, bbox)
- system (cmd)
- box = open (bbox).read ()
- m = re.match ('^%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)',
- box)
- gr = []
+
+def ps_page_count (ps_name):
+ header = open (ps_name).read (1024)
+ m = re.search ('\n%%Pages: ([0-9]+)', header)
if m:
- gr = map (string.atoi, m.groups ())
-
- return gr
-
-def make_preview (name):
- ## ly2dvi/lilypond-book discrepancy
- preview_ps = name + '.preview.ps'
- if not os.path.isfile (preview_ps):
- preview_ps = name + '.eps'
- bbox = get_bbox (preview_ps)
- print 'bbox:' + `bbox`
- trans_ps = name + '.trans.ps'
- png = name + '.png'
-
- margin = 0
- fo = open (trans_ps, 'w')
- fo.write ('%d %d translate\n' % (-bbox[0] + margin,
- -bbox[1] + margin))
- fo.close ()
-
- x = (2* margin + bbox[2] - bbox[0]) \
- * __main__.preview_resolution / 72.0
- y = (2* margin + bbox[3] - bbox[1]) \
- * __main__.preview_resolution / 72.0
- if x == 0:
- x = 1
- if y == 0:
- y = 1
-
- cmd = r'''gs -g%dx%d -sDEVICE=pnggray -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=%s -r%d -dNOPAUSE %s %s -c quit ''' % \
- (x, y, png, __main__.preview_resolution, trans_ps, preview_ps)
-
- system (cmd)
+ return string.atoi (m.group (1))
+ return 0
+
+def make_ps_images (ps_name, resolution = 90, papersize = "a4",
+ rename_page1_p = 0):
+ base = os.path.basename (re.sub (r'\.e?ps', '', ps_name))
+ header = open (ps_name).read (1024)
+
+ png1 = base + '.png'
+ pngn = base + '-page%d.png'
+ output_file = pngn
+ multi_page = re.search ('\n%%Pages: ', header)
+
+ # png16m is because Lily produces color nowadays.
+ if not multi_page:
+
+ # GS can produce empty 2nd page if pngn is used.
+ output_file = png1
+ cmd = r'''gs\
+ -dEPSCrop\
+ -dGraphicsAlphaBits=4\
+ -dNOPAUSE\
+ -dTextAlphaBits=4\
+ -sDEVICE=png16m\
+ -sOutputFile='%(output_file)s'\
+ -sPAPERSIZE=%(papersize)s\
+ -q\
+ -r%(resolution)d\
+ '%(ps_name)s'\
+ -c showpage\
+ -c quit ''' % vars ()
+ else:
+ cmd = r'''gs\
+ -s\
+ -dGraphicsAlphaBits=4\
+ -dNOPAUSE\
+ -dTextAlphaBits=4\
+ -sDEVICE=png16m\
+ -sOutputFile='%(output_file)s'\
+ -sPAPERSIZE=%(papersize)s\
+ -q\
+ -r%(resolution)d\
+ '%(ps_name)s'\
+ -c quit''' % vars ()
+
+ remove = glob.glob (png1) + glob.glob (base + '-page*.png')
+ map (os.unlink, remove)
status = system (cmd)
signal = 0xf & status
exit_status = status >> 8
-
+
if status:
- os.unlink (png)
- error (_ ("Removing output file"))
+ remove = glob.glob (png1) + glob.glob (base + '-page*.png')
+ map (os.unlink, remove)
+ error (_ ("%s exited with status: %d") % ('GS', status))
exit (1)
+
+ if rename_page1_p and multi_page:
+ os.rename (pngn % 1, png1)
+ files = glob.glob (png1) + glob.glob (re.sub ('%d', '*', pngn))
+ return files
+
+class NonDentedHeadingFormatter (optparse.IndentedHelpFormatter):
+ def format_heading(self, heading):
+ if heading:
+ return heading[0].upper() + heading[1:] + ':\n'
+ return ''
+ def format_option_strings(self, option):
+ sep = ' '
+ if option._short_opts and option._long_opts:
+ sep = ','
+
+ metavar = ''
+ if option.takes_value():
+ metavar = '=%s' % option.metavar or option.dest.upper()
+
+ return "%3s%s %s%s" % (" ".join (option._short_opts),
+ sep,
+ " ".join (option._long_opts),
+ metavar)
+
+ def format_usage(self, usage):
+ return _("Usage: %s\n") % usage
+
+ def format_description(self, description):
+ return description
+
+def get_option_parser (*args, **kwargs):
+ p = optparse.OptionParser (*args, **kwargs)
+ p.formatter = NonDentedHeadingFormatter ()
+ return p