3 # convert-ly.py -- Update old LilyPond input files (fix name?)
4 # converting rules are found in python/convertrules.py
6 # This file is part of LilyPond, the GNU music typesetter.
8 # Copyright (C) 1998--2012 Han-Wen Nienhuys <hanwen@xs4all.nl>
9 # Jan Nieuwenhuizen <janneke@gnu.org>
11 # LilyPond is free software: you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation, either version 3 of the License, or
14 # (at your option) any later version.
16 # LilyPond is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
35 ly.require_python_version ()
39 lilypond_version_re_str = '\\\\version *\"([0-9.]+)"'
40 lilypond_version_re = re.compile (lilypond_version_re_str)
42 lilypond_version_strict_re_str = '\\\\version *\"([0-9]+[.][0-9]+[.][0-9]+)"'
43 lilypond_version_strict_re = re.compile (lilypond_version_strict_re_str)
46 _ ('''Update LilyPond input to newer version. By default, update from the
47 version taken from the \\version command, to the current LilyPond version.''')
50 $ convert-ly -e old.ly
51 $ convert-ly --from=2.3.28 --to=2.5.21 foobar.ly > foobar-new.ly
54 copyright = ('Jan Nieuwenhuizen <janneke@gnu.org>',
55 'Han-Wen Nienhuys <hanwen@xs4all.nl>')
57 program_name = os.path.basename (sys.argv[0])
58 program_version = '@TOPLEVEL_VERSION@'
60 authors = ('Jan Nieuwenhuizen <janneke@gnu.org>',
61 'Han-Wen Nienhuys <hanwen@xs4all.nl>')
64 ly.progress ('%s (GNU LilyPond) %s\n' % (program_name, program_version))
68 ly.encoded_write (sys.stdout, '''
75 ''' % ( _ ('Copyright (c) %s by') % '2001--2012',
77 _ ('Distributed under terms of the GNU General Public License.'),
78 _ ('It comes with NO WARRANTY.')))
80 def get_option_parser ():
81 p = ly.get_option_parser (usage=_ ("%s [OPTION]... FILE") % 'convert-ly',
82 description=help_summary,
83 add_help_option=False)
85 p.version="@TOPLEVEL_VERSION@"
86 p.add_option("--version",
88 help=_ ("show version number and exit"))
90 p.add_option("-h", "--help",
92 help=_ ("show this help and exit"))
94 p.add_option ('-f', '--from',
96 metavar=_ ("VERSION"),
98 help=_ ("start from VERSION [default: \\version found in file]"),
101 p.add_option ('-e', '--edit', help=_ ("edit in place"),
104 p.add_option ("-l", "--loglevel",
105 help=_ ("Print log messages according to LOGLEVEL "
106 "(NONE, ERROR, WARNING, PROGRESS (default), DEBUG)"),
107 metavar=_ ("LOGLEVEL"),
109 callback=ly.handle_loglevel_option,
112 p.add_option ('-n', '--no-version',
113 help=_ ("do not add \\version command if missing"),
115 dest='skip_version_add',
118 p.add_option ('-c', '--current-version',
119 help=_ ("force updating \\version number to %s") % program_version,
121 dest='force_current_version',
124 p.add_option ('-d', '--diff-version-update',
125 help=_ ("only update \\version number if file is modified"),
127 dest='diff_version_update',
130 p.add_option ("-s", '--show-rules',
131 help=_ ("show rules [default: -f 0, -t %s]") % program_version,
133 action='store_true', default=False)
135 p.add_option ('-t', '--to',
136 help=_ ("convert to VERSION [default: %s]") % program_version,
137 metavar=_ ('VERSION'),
141 p.add_option ('-w', '--warranty', help=_ ("show warranty and copyright"),
144 p.add_option_group ('',
146 _ ("Report bugs via %s")
147 % 'http://post.gmane.org/post.php'
148 '?group=gmane.comp.gnu.lilypond.bugs') + '\n')
154 def str_to_tuple (s):
155 return tuple ([int(n) for n in s.split ('.')])
158 return '.'.join (['%s' % x for x in t])
160 def version_cmp (t1, t2):
166 def get_conversions (from_version, to_version):
167 def is_applicable (v, f = from_version, t = to_version):
168 return version_cmp (v[0], f) > 0 and version_cmp (v[0], t) <= 0
169 return filter (is_applicable, convertrules.conversions)
171 def latest_version ():
172 return convertrules.conversions[-1][0]
174 def show_rules (file, from_version, to_version):
175 for x in convertrules.conversions:
176 if (not from_version or x[0] > from_version) \
177 and (not to_version or x[0] <= to_version):
178 ly.encoded_write (file, '%s: %s\n' % (tup_to_str (x[0]), x[2]))
180 def do_conversion (str, from_version, to_version):
181 """Apply conversions from FROM_VERSION to TO_VERSION. Return
182 tuple (LAST,STR), with the last successful conversion and the resulting
184 conv_list = get_conversions (from_version, to_version)
186 ly.progress (_ ("Applying conversion: "), newline = False)
191 last_conversion = to_version
193 if x != conv_list[-1]:
194 ly.progress (tup_to_str (x[0]), newline = False)
195 ly.progress (', ', newline = False)
197 ly.progress (tup_to_str (x[0]))
199 last_conversion = x[0]
201 except convertrules.FatalConversionError:
202 ly.error (_ ("Error while converting")
204 + _ ("Stopping at last successful rule"))
206 return (last_conversion, str)
210 def guess_lilypond_version (input):
211 m = lilypond_version_strict_re.search (input)
214 m = lilypond_version_re.search (input)
216 raise InvalidVersion (m.group (1))
220 class FatalConversionError (Exception):
223 class UnknownVersion (Exception):
226 class InvalidVersion (Exception):
227 def __init__ (self, version):
228 self.version = version
230 def do_one_file (infile_name):
231 ly.progress (_ ("Processing `%s\'... ") % infile_name, True)
234 infile = open (infile_name, 'r')
235 input = infile.read ()
238 input = sys.stdin.read ()
242 if global_options.from_version:
243 from_version = global_options.from_version
245 guess = guess_lilypond_version (input)
247 raise UnknownVersion ()
248 from_version = str_to_tuple (guess)
250 if global_options.to_version:
251 to_version = global_options.to_version
253 to_version = latest_version ()
255 if len (from_version) != 3:
256 raise InvalidVersion (".".join ([str(n) for n in from_version]))
259 (last, result) = do_conversion (input, from_version, to_version)
262 if global_options.force_current_version and last == to_version:
263 last = str_to_tuple (program_version)
265 if global_options.diff_version_update:
267 # check the y in x.y.z (minor version number)
268 previous_stable = (last[0], 2*(last[1]/2), 0)
269 if ((last[0:2] != from_version[0:2]) and
270 (previous_stable > from_version)):
271 # previous stable version
272 last = previous_stable
274 # make no (actual) change to the version number
277 newversion = r'\version "%s"' % tup_to_str (last)
278 if lilypond_version_re.search (result):
279 result = re.sub (lilypond_version_re_str,
280 '\\' + newversion, result)
281 elif not global_options.skip_version_add:
282 result = newversion + '\n' + result
286 if global_options.edit:
288 os.remove(infile_name + '~')
291 os.rename (infile_name, infile_name + '~')
292 outfile = open (infile_name, 'w')
297 outfile.write (result)
302 opt_parser = get_option_parser()
303 (options, args) = opt_parser.parse_args ()
309 if options.from_version:
310 options.from_version = str_to_tuple (options.from_version)
311 if options.to_version:
312 options.to_version = str_to_tuple (options.to_version)
314 options.outfile_name = ''
315 global global_options
316 global_options = options
318 if not args and not options.show_rules:
319 opt_parser.print_help ()
325 files = do_options ()
327 # should parse files[] to read \version?
328 if global_options.show_rules:
329 show_rules (sys.stdout, global_options.from_version, global_options.to_version)
337 elif not os.path.isfile (f):
338 ly.error (_ ("%s: Unable to open file") % f)
344 except UnknownVersion:
345 ly.error (_ ("%s: Unable to determine version. Skipping") % f)
346 except InvalidVersion:
347 # Compat code for 2.x and 3.0 syntax ("except .. as v" doesn't
348 # work in python 2.4!):
349 t, v, b = sys.exc_info ()
350 ly.error (_ ("%s: Invalid version string `%s' \n"
351 "Valid version strings consist of three numbers, "
352 "separated by dots, e.g. `2.8.12'") % (f, v.version) )