X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=python%2Flilylib.py;h=a911cac23f0a2f8bdc77503a0e0c886becc7fa6f;hb=b872748c6aa8bb721ced458691b38ac2fac5dfc8;hp=3bf77f6f44c5a439cfaf799e24d76275d685390e;hpb=55ac733b69643a6bc6a83b706c65cb56efd388ef;p=lilypond.git diff --git a/python/lilylib.py b/python/lilylib.py index 3bf77f6f44..a911cac23f 100644 --- a/python/lilylib.py +++ b/python/lilylib.py @@ -1,6 +1,6 @@ # This file is part of LilyPond, the GNU music typesetter. # -# Copyright (C) 1998--2011 Han-Wen Nienhuys +# Copyright (C) 1998--2015 Han-Wen Nienhuys # Jan Nieuwenhuizen # # LilyPond is free software: you can redistribute it and/or modify @@ -23,6 +23,7 @@ import re import shutil import sys import optparse +import time ################################################################ # Users of python modules should include this snippet @@ -39,21 +40,32 @@ try: import gettext t = gettext.translation ('lilypond', localedir) _ = t.ugettext + ungettext = t.ungettext except: def _ (s): - return s + return s + def ungettext (s, p, n): + if n == 1: + return s + return p underscore = _ # Urg, Python 2.4 does not define stderr/stdout encoding # Maybe guess encoding from LANG/LC_ALL/LC_CTYPE? +reload (sys) +sys.setdefaultencoding ('utf-8') +import codecs +sys.stdout = codecs.getwriter ('utf8') (sys.stdout) +sys.stderr = codecs.getwriter ('utf8') (sys.stderr) + def encoded_write(f, s): - f.write (s.encode (f.encoding or 'utf_8')) + f.write (s.encode (f.encoding or 'utf-8', 'replace')) # ugh, Python 2.5 optparse requires Unicode strings in some argument # functions, and refuse them in some other places def display_encode (s): - return s.encode (sys.stderr.encoding or 'utf_8') + return s.encode (sys.stderr.encoding or 'utf-8', 'replace') # Lilylib globals. program_version = '@TOPLEVEL_VERSION@' @@ -71,29 +83,83 @@ if at_re.match (program_version): else: program_version = "unknown" + +# Logging framework: We have the following output functions: +# error +# warning +# progress +# debug + +loglevels = {"NONE":0, "ERROR":1, "WARN":2, "BASIC":3, "PROGRESS":4, "INFO":5, "DEBUG":6} + +loglevel = loglevels["PROGRESS"] + +def set_loglevel (l): + global loglevel + newlevel = loglevels.get (l, -1) + if newlevel > 0: + debug_output (_ ("Setting loglevel to %s") % l) + loglevel = newlevel + else: + error (_ ("Unknown or invalid loglevel '%s'") % l) + + +def handle_loglevel_option (option, opt_str, value, parser, *args): + if value: + set_loglevel (value); + elif args: + set_loglevel (args[0]); + +def is_loglevel (l): + global loglevel + return loglevel >= loglevels[l]; + +def is_verbose (): + return is_loglevel ("DEBUG") + def stderr_write (s): encoded_write (sys.stderr, s) -def warning (s): - stderr_write (program_name + ": " + _ ("warning: %s") % s + '\n') +def print_logmessage (level, s, fullmessage = True, newline = True): + if (is_loglevel (level)): + if fullmessage: + stderr_write (program_name + ": " + s + '\n') + elif newline: + stderr_write (s + '\n') + else: + stderr_write (s) def error (s): - stderr_write (program_name + ": " + _ ("error: %s") % s + '\n') + print_logmessage ("ERROR", _ ("error: %s") % s); + +def warning (s): + print_logmessage ("WARN", _ ("warning: %s") % s); + +def basic_progress (s): + print_logmessage ("BASIC", s); + +def progress (s, fullmessage = False, newline = True): + print_logmessage ("PROGRESS", s, fullmessage, newline); + +def debug_output (s, fullmessage = False, newline = True): + print_logmessage ("DEBUG", s, fullmessage, newline); -progress = stderr_write def require_python_version (): if sys.hexversion < 0x02040000: - stderr_write ("Python 2.4 or newer is required to run this program.\n\ + error ("Python 2.4 or newer is required to run this program.\n\ Please upgrade Python from http://python.org/download/, and if you use MacOS X,\n\ please read 'Setup for MacOS X' in Application Usage.") os.system ("open http://python.org/download/") sys.exit (2) -# Modified version of the commands.mkarg(x), which always uses -# double quotes (since Windows can't handle the single quotes: +# A modified version of the commands.mkarg(x) that always uses +# double quotes (since Windows can't handle the single quotes) +# and escapes the characters \, $, ", and ` for unix shells. def mkarg(x): + if os.name == 'nt': + return ' "%s"' % x s = ' "' for c in x: if c in '\\$"`': @@ -112,6 +178,7 @@ def subprocess_system (cmd, ignore_error=False, progress_p=True, be_verbose=False, + redirect_output=False, log_file=None): import subprocess @@ -119,46 +186,58 @@ def subprocess_system (cmd, name = command_name (cmd) error_log_file = '' - if be_verbose: - show_progress = 1 - progress (_ ("Invoking `%s\'") % cmd) + if redirect_output: + progress (_ ("Processing %s.ly") % log_file) else: - progress ( _("Running %s...") % name) - + if be_verbose: + show_progress = 1 + progress (_ ("Invoking `%s\'") % cmd) + else: + progress ( _("Running %s...") % name) stdout_setting = None + stderr_setting = None if not show_progress: - stdout_setting = subprocess.PIPE + stdout_setting = subprocess.PIPE + + if redirect_output: + stderr_filename = log_file + '.log' + stderr_setting = open(stderr_filename, 'w') proc = subprocess.Popen (cmd, - shell=True, - universal_newlines=True, - stdout=stdout_setting, - stderr=stdout_setting) + shell=True, + universal_newlines=True, + stdout=stdout_setting, + stderr=stderr_setting) log = '' - if show_progress: - retval = proc.wait() + if redirect_output: + while proc.poll()==None: + time.sleep(0.01) + retval = proc.returncode + stderr_setting.close() else: - log = proc.communicate () - retval = proc.returncode - + if show_progress: + retval = proc.wait() + else: + log = proc.communicate () + retval = proc.returncode if retval: - print >>sys.stderr, 'command failed:', cmd - if retval < 0: - print >>sys.stderr, "Child was terminated by signal", -retval - elif retval > 0: - print >>sys.stderr, "Child returned", retval - - if ignore_error: - print >>sys.stderr, "Error ignored" - else: - if not show_progress: - print log[0] - print log[1] - sys.exit (1) + print >>sys.stderr, 'command failed:', cmd + if retval < 0: + print >>sys.stderr, "Child was terminated by signal", -retval + elif retval > 0: + print >>sys.stderr, "Child returned", retval + + if ignore_error: + print >>sys.stderr, "Error ignored by lilylib" + else: + if not show_progress: + print log[0] + print log[1] + sys.exit (1) return abs (retval) @@ -166,28 +245,29 @@ def ossystem_system (cmd, ignore_error=False, progress_p=True, be_verbose=False, + redirect_output=False, log_file=None): name = command_name (cmd) if be_verbose: - show_progress = 1 - progress (_ ("Invoking `%s\'") % cmd) + show_progress = 1 + progress (_ ("Invoking `%s\'") % cmd) else: - progress ( _("Running %s...") % name) + progress ( _("Running %s...") % name) retval = os.system (cmd) if retval: - print >>sys.stderr, 'command failed:', cmd - if retval < 0: - print >>sys.stderr, "Child was terminated by signal", -retval - elif retval > 0: - print >>sys.stderr, "Child returned", retval + print >>sys.stderr, 'command failed:', cmd + if retval < 0: + print >>sys.stderr, "Child was terminated by signal", -retval + elif retval > 0: + print >>sys.stderr, "Child returned", retval - if ignore_error: - print >>sys.stderr, "Error ignored" - else: - sys.exit (1) + if ignore_error: + print >>sys.stderr, "Error ignored" + else: + sys.exit (1) return abs (retval) @@ -201,7 +281,7 @@ if sys.platform == 'mingw32': def strip_extension (f, ext): (p, e) = os.path.splitext (f) if e == ext: - e = '' + e = '' return p + e @@ -209,34 +289,34 @@ def search_exe_path (name): p = os.environ['PATH'] exe_paths = p.split (':') for e in exe_paths: - full = os.path.join (e, name) - if os.path.exists (full): - return full + full = os.path.join (e, name) + if os.path.exists (full): + return full return None def print_environment (): for (k,v) in os.environ.items (): - sys.stderr.write ("%s=\"%s\"\n" % (k, v)) + sys.stderr.write ("%s=\"%s\"\n" % (k, v)) class NonDentedHeadingFormatter (optparse.IndentedHelpFormatter): def format_heading(self, heading): - if heading: - return heading[0].upper() + heading[1:] + ':\n' - return '' + 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 = ',' + sep = ' ' + if option._short_opts and option._long_opts: + sep = ',' - metavar = '' - if option.takes_value(): - metavar = '=%s' % option.metavar or option.dest.upper() + 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) + return "%3s%s %s%s" % (" ".join (option._short_opts), + sep, + " ".join (option._long_opts), + metavar) # Only use one level of indentation (even for groups and nested groups), # since we don't indent the headeings, either @@ -253,10 +333,17 @@ class NonDentedHeadingFormatter (optparse.IndentedHelpFormatter): return _("Usage: %s") % usage + '\n' def format_description(self, description): - return description + return description + +class NonEmptyOptionParser (optparse.OptionParser): + "A subclass of OptionParser that gobbles empty string arguments." + + def parse_args (self, args=None, values=None): + options, args = optparse.OptionParser.parse_args (self, args, values) + return options, filter (None, args) def get_option_parser (*args, **kwargs): - p = optparse.OptionParser (*args, **kwargs) + p = NonEmptyOptionParser (*args, **kwargs) p.formatter = NonDentedHeadingFormatter () p.formatter.set_parser (p) return p