#!/usr/local/bin/python2.5
#
# convert-ly.py -- Update old LilyPond input files (fix name?)
#
# source file of the GNU LilyPond music typesetter
#
# (c) 1998--2007  Han-Wen Nienhuys <hanwen@xs4all.nl>
#                 Jan Nieuwenhuizen <janneke@gnu.org>
#
# converting rules are found in python/convertrules.py
#

import os
import sys
import string
import re

"""

This generic code used for all python scripts.

The quotes are to ensure that the source .py file can still be
run as a python script, but does not include any sys.path handling.
Otherwise, the lilypond-book calls inside the build
might modify installed .pyc files.

"""

for d in ['/usr/local/share/lilypond/2.10.33',
	  '/usr/local/lib/lilypond/2.10.33']:
    sys.path.insert (0, os.path.join (d, 'python'))

# dynamic relocation, for GUB binaries.
bindir = os.path.abspath (os.path.split (sys.argv[0])[0])
for p in ['share', 'lib']:
    datadir = os.path.abspath (bindir + '/../%s/lilypond/current/python/' % p)
    sys.path.insert (0, datadir)
"""
"""

import lilylib as ly
global _;_=ly._

import convertrules

lilypond_version_re_str = '\\\\version *\"([0-9.]+)"'
lilypond_version_re = re.compile (lilypond_version_re_str)


help_summary = _ (
'''Update LilyPond input to newer version.  By default, update from the
version taken from the \\version command, to the current LilyPond version.

Examples:

  convert-ly -e old.ly
  convert-ly --from=2.3.28 --to 2.5.21 foobar.ly
''')

copyright = ('Jan Nieuwenhuizen <janneke@gnu.org>',
         'Han-Wen Nienhuys <hanwen@cs.uu.nl>')

program_name = os.path.basename (sys.argv[0])
program_version = '2.10.33'

def warning (s):
    sys.stderr.write (program_name + ": " + _ ("warning: %s") % s + '\n')

def error (s):
    sys.stderr.write (program_name + ": " + _ ("error: %s") % s + '\n')

def identify (port=sys.stderr):
    port.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version))

def warranty ():
    identify ()
    sys.stdout.write ('''
Copyright (c) %s by

  Han-Wen Nienhuys
  Jan Nieuwenhuizen

%s
%s
'''  ( '2001--2006',
       _('Distributed under terms of the GNU General Public License.'),
       _('It comes with NO WARRANTY.')))



def get_option_parser ():
    p = ly.get_option_parser (usage='convert-ly [OPTIONS] FILE',
                  version="2.10.33",
                  description=help_summary)

    p.add_option ('-f', '--from', 
              action="store",
              metavar=_ ("VERSION"),
              dest="from_version",
              help=_('start from VERSION [default: \\version found in file]'),
              default='')
    
    p.add_option ('-e', '--edit', help=_('edit in place'),
              action='store_true')
    p.add_option ('-n', '--no-version',
              help=_ ('do not add \\version command if missing'),
              action='store_true',
              dest='skip_version_add',
              default=False)
    
    p.add_option ("-s", '--show-rules',
              help=_('print rules [default: --from=0, --to=2.10.33]'),
              dest='show_rules',
              action='store_true', default=False)
    
    p.add_option ('-t', '--to',
              help=_('convert to VERSION [default: 2.10.33]'),
              metavar=_('VERSION'),
              action='store',
              dest="to_version",
              default='')

    p.add_option_group  ('bugs',
                 description='''Report bugs via http://post.gmane.org/post.php'''
                 '''?group=gmane.comp.gnu.lilypond.bugs\n''')
    
    return p



def str_to_tuple (s):
    return tuple (map (int, string.split (s, '.')))

def tup_to_str (t):
    return string.join (map (lambda x: '%s' % x, list (t)), '.')

def version_cmp (t1, t2):
    for x in [0, 1, 2]:
        if t1[x] - t2[x]:
            return t1[x] - t2[x]
    return 0

def get_conversions (from_version, to_version):
    def is_applicable (v, f = from_version, t = to_version):
        return version_cmp (v[0], f) > 0 and version_cmp (v[0], t) <= 0
    return filter (is_applicable, convertrules.conversions)

def latest_version ():
    return convertrules.conversions[-1][0]

def show_rules (file, from_version, to_version):
    for x in convertrules.conversions:
        if (not from_version or x[0] > from_version) \
           and (not to_version or x[0] <= to_version):
            file.write  ('%s: %s\n' % (tup_to_str (x[0]), x[2]))

def do_conversion (str, from_version, to_version):
    """Apply conversions from FROM_VERSION to TO_VERSION.  Return
tuple (LAST,STR), with the last succesful conversion and the resulting
string."""
    conv_list = get_conversions (from_version, to_version)

    if convertrules.error_file:
        convertrules.error_file.write (_ ("Applying conversion: "))
        
    last_conversion = ()
    try:
        for x in conv_list:
            convertrules.error_file.write (tup_to_str (x[0]))
            if x != conv_list[-1]:
                convertrules.error_file.write (', ')
            str = x[1] (str)
            last_conversion = x[0]

    except convertrules.FatalConversionError:
        convertrules.error_file.write ('\n'
                                       + _ ("Error while converting")
                                       + '\n'
                                       + _ ("Stopping at last succesful rule")
                                       + '\n')

    return (last_conversion, str)



def guess_lilypond_version (filename):
    s = open (filename).read ()
    m = lilypond_version_re.search (s)
    if m:
        return m.group (1)
    else:
        return ''

class FatalConversionError:
    pass

class UnknownVersion:
    pass

def do_one_file (infile_name):
    sys.stderr.write (_ ("Processing `%s\'... ") % infile_name)
    sys.stderr.write ('\n')

    from_version = None
    to_version = None
    if global_options.from_version:
        from_version = global_options.from_version
    else:
        guess = guess_lilypond_version (infile_name)
        if not guess:
            raise UnknownVersion ()
        from_version = str_to_tuple (guess)

    if global_options.to_version:
        to_version = global_options.to_version
    else:
        to_version = latest_version ()


    if infile_name:
        infile = open (infile_name, 'r')
    else:
        infile = sys.stdin


    (last, result) = do_conversion (infile.read (), from_version, to_version)
    infile.close ()

    if last:
        newversion = r'\version "%s"' % tup_to_str (last)
        if lilypond_version_re.search (result):
            result = re.sub (lilypond_version_re_str,
                     '\\' + newversion, result)
        elif not global_options.skip_version_add:
            result = newversion + '\n' + result
            
        convertrules.error_file.write ('\n')            
    
        if global_options.edit:
            try:
                os.remove(infile_name + '~')
            except:
                pass
            os.rename (infile_name, infile_name + '~')
            outfile = open (infile_name, 'w')
        else:
            outfile = sys.stdout


        outfile.write (result)

    sys.stderr.flush ()

def do_options ():
    opt_parser = get_option_parser()
    (options, args) = opt_parser.parse_args ()


    if options.from_version:
        options.from_version = str_to_tuple (options.from_version)
    if options.to_version:
        options.to_version = str_to_tuple (options.to_version)

    options.outfile_name = ''
    global global_options
    global_options = options

    if not args and not options.show_rules:
        opt_parser.print_help ()
        sys.exit (2)

    return args

def main ():
    files = do_options ()

    # should parse files[] to read \version?
    if global_options.show_rules:
        show_rules (sys.stdout, global_options.from_version, global_options.to_version)
        sys.exit (0)

    identify (sys.stderr)

    for f in files:
        if f == '-':
            f = ''
        elif not os.path.isfile (f):
            error (_ ("can't open file: `%s'") % f)
            if len (files) == 1:
                sys.exit (1)
            continue
        try:
            do_one_file (f)
        except UnknownVersion:
            error (_ ("can't determine version for `%s'. Skipping") % f)

    sys.stderr.write ('\n')

main ()
