#
# source file of the GNU LilyPond music typesetter
#
-# (c) 1998--2005 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 glob
+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
-import os
-import sys
datadir = '@local_lilypond_datadir@'
if not os.path.isdir (datadir):
datadir = '@lilypond_datadir@'
-# 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', _ ("print 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:
def warranty ():
identify (sys.stdout)
sys.stdout.write ('\n')
- sys.stdout.write (_ ("Copyright (c) %s by") % '1998--2005')
+ 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 (__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 (i)
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]
return __main__.temp_dir
def command_name (cmd):
-
+ # Strip all stuf after command,
# deal with "((latex ) >& 1 ) .." too
- cmd = re.match ("([\(\)]*)([^ ]*)", cmd).group(2)
+ cmd = re.match ('([\(\)]*)([^\\\ ]*)', cmd).group (2)
return os.path.basename (cmd)
def error_log (name):
redirect = ''
error_log_file = ''
- if __main__.verbose_p:
+ if be_verbose:
progress (_ ("Opening pipe `%s\'") % cmd)
else:
error_log_file = error_log (command_name (cmd))
if status:
error (_ ("`%s\' failed (%d)") % (cmd, exit_status))
- if not __main__.verbose_p:
+ if not be_verbose:
contents = open (error_log_file).read ()
if contents:
error (_ ("The error log is as follows:"))
exit (1)
- if __main__.verbose_p:
+ if be_verbose:
progress ('\n')
if 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
name = command_name (cmd)
error_log_file = ''
+
+ ## UGH
+ be_verbose = get_global_option('verbose_p', 'verbose')
+ pseudo_filter = get_global_option ('pseudo_filter_p', 'pseudo_filter')
- if __main__.verbose_p:
+ if be_verbose:
progress_p = 1
progress (_ ("Invoking `%s\'") % cmd)
else:
if not progress_p:
error_log_file = error_log (name)
redirect = ' 1>/dev/null 2>' + error_log_file
- elif __main__.pseudo_filter_p:
+ elif pseudo_filter:
redirect = ' 1>/dev/null'
status = os.system (cmd + redirect)
msg = _ ("`%s\' failed (%s)") % (name, exit_type)
if ignore_error:
- if __main__.verbose_p:
+ if be_verbose:
warning (msg + ' ' + _ ("(ignored)"))
else:
error (msg)
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')
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',
- 'GS_FONTPATH' : "",
- 'GS_LIB' : "",
- }
-
- # $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))
-BOUNDING_BOX_RE = '^%%BoundingBox: (-?[0-9]+) (-?[0-9]+) (-?[0-9]+) (-?[0-9]+)'
-def get_bbox (filename):
- bbox = filename + '.bbox'
- ## -sOutputFile does not work with bbox?
- cmd = 'gs -sDEVICE=bbox -q -dNOPAUSE %s -c showpage -c quit 2>%s' % \
- (filename, bbox)
- system (cmd, progress_p = 1)
- box = open (bbox).read ()
- m = re.match (BOUNDING_BOX_RE, box)
- gr = []
- if m:
- gr = map (string.atoi, m.groups ())
-
- return gr
-
-def make_ps_images (ps_name, resolution = 90, papersize = "a4"):
- ## todo:
- ## have better algorithm for deciding when to crop page,
- ## and when to show full page
- base = re.sub (r'\.e?ps', '', ps_name)
-
+def ps_page_count (ps_name):
header = open (ps_name).read (1024)
+ m = re.search ('\n%%Pages: ([0-9]+)', header)
+ if m:
+ return string.atoi (m.group (1))
+ return 0
- match = re.search (BOUNDING_BOX_RE, header, re.MULTILINE)
- bbox = []
- if match:
- bbox = map (string.atoi, match.groups ())
+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)
- cmd = ''
- if multi_page == None:
-
- if bbox == []:
- bbox = get_bbox (ps_name)
-
- trans_ps = ps_name + '.trans.ps'
- output_file = re.sub (r'\.e?ps', '.png', ps_name)
-
- # need to have margin, otherwise edges of letters will
- # be cropped off.
-
- margin = 3
- 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]) \
- * resolution / 72.0
- y = (2* margin + bbox[3] - bbox[1]) \
- * resolution / 72.0
- if x == 0:
- x = 1
- if y == 0:
- y = 1
+ # 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\
- -g%(x)d%(y)d\
+ -dEPSCrop\
-dGraphicsAlphaBits=4\
-dNOPAUSE\
-dTextAlphaBits=4\
-sPAPERSIZE=%(papersize)s\
-q\
-r%(resolution)d\
- %(trans_ps)s\
'%(ps_name)s'\
-c showpage\
-c quit ''' % vars ()
-
- rms = glob.glob (base + '-page*.png')
- map (os.unlink, rms)
else:
- output_file = re.sub (r'\.e?ps', '-page%d.png', ps_name)
-
- rmfile = base + '.png'
- if os.path.isfile (rmfile):
- os.unlink (rmfile)
-
cmd = r'''gs\
-s\
-dGraphicsAlphaBits=4\
'%(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)
-
- cmd = r'''gs -s -sDEVICE=pnggray -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=%s -dNOPAUSE -r%d %s -c quit''' % (output_file,
- resolution, ps_name)
-
- files = glob.glob (re.sub ('%d', '*', output_file))
+ 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