Spaces:
Sleeping
Sleeping
#!/usr/bin/env python | |
# update-snippets.py | |
# | |
# This file is part of LilyPond, the GNU music typesetter. | |
# | |
# Copyright (C) 2007--2020 John Mandereau <[email protected]>> | |
# | |
# LilyPond is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# LilyPond is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with LilyPond. If not, see <http://www.gnu.org/licenses/>. | |
# USAGE: update-snippets.py REFERENCE-DIR TARGET-DIR FILES | |
# | |
# update ly snippets in TARGET-DIR/FILES with snippets from REFERENCE-DIR/FILES | |
# | |
# More precisely, each existing FILE in TARGET-DIR is matched to the FILE in | |
# REFERENCE-DIR (it the latter does not exist, a warning is given). | |
# | |
# Shell wildcards expansion is performed on FILES. | |
# This script currently supports Texinfo format. | |
# Ly snippets preceded with a line containing '@c KEEP LY' in TARGET-DIR/FILES | |
# will not be updated. | |
# An error occurs if REFERENCE-DIR/FILE and TARGET-DIR/FILE do not have the | |
# same snippets count. | |
import sys | |
import os | |
import glob | |
import re | |
from functools import reduce | |
print("update-snippets.py") | |
comment_re = re.compile( | |
r'(?<!@)(@c(?:omment)? .*?\n|^@ignore\n.*?\n@end ignore\n)', re.M | re.S) | |
snippet_re = re.compile( | |
r'^(@lilypond(?:file)?(?:\[.*?\])?\s*\{.+?\}|@lilypond(?:\[.*?\])?(?:.|\n)+?@end lilypond)', re.M) | |
def snippet_split(l): | |
r = [] | |
for s in [s for s in l if s]: | |
if s.startswith('@c ') or s.startswith('@ignore\n') or s.startswith('@comment '): | |
r.append(s) | |
else: | |
r += [t for t in snippet_re.split(s) if t] | |
return r | |
def count_snippet(l): | |
k = 0 | |
for s in l: | |
if s.startswith('@lilypond'): | |
k += 1 | |
return k | |
def find_next_snippet(l, k): | |
while not l[k].startswith('@lilypond'): | |
k += 1 | |
return k | |
exit_code = 0 | |
def update_exit_code(code): | |
global exit_code | |
exit_code = max(code, exit_code) | |
ref_dir, target_dir = sys.argv[1:3] | |
file_patterns = sys.argv[3:] | |
total_snippet_count = 0 | |
changed_snippets_count = 0 | |
for pattern in file_patterns: | |
files = glob.glob(os.path.join(target_dir, pattern)) | |
for file in files: | |
ref_file = os.path.join(ref_dir, os.path.basename(file)) | |
if not os.path.isfile(ref_file): | |
sys.stderr.write( | |
"Warning: %s: no such file.\nReference file for %s not found.\n" % (ref_file, file)) | |
continue | |
f = open(file, 'r', encoding='utf8') | |
target_source = comment_re.split(f.read()) | |
f.close() | |
if reduce(lambda x, y: x or y, ['-- SKELETON FILE --' in s for s in target_source]): | |
sys.stderr.write("Skipping skeleton file %s\n" % file) | |
continue | |
g = open(ref_file, 'r', encoding='utf8') | |
ref_source = comment_re.split(g.read()) | |
target_source = snippet_split(target_source) | |
ref_source = snippet_split(ref_source) | |
if '' in target_source or '' in ref_source: | |
raise RuntimeError( | |
"target_source and ref_source must not be empty") | |
snippet_count = count_snippet(target_source) | |
if not snippet_count == count_snippet(ref_source): | |
update_exit_code(1) | |
sys.stderr.write("Error: %s and %s have different snippet counts.\n\ | |
Update translation by at least adding a @lilypond block where necessary, then rerun this script.\n" % (ref_file, file)) | |
continue | |
total_snippet_count += snippet_count | |
c = 0 | |
k = -1 | |
for j in range(len(target_source)): | |
if target_source[j].startswith('@lilypond'): | |
k = find_next_snippet(ref_source, k+1) | |
if j > 0 and (not target_source[j-1].startswith('@c KEEP LY')) and target_source[j] != ref_source[k]: | |
target_source[j] = ref_source[k] | |
c += 1 | |
changed_snippets_count += 1 | |
f = open(file, 'w', encoding='utf8') | |
f.write(''.join(target_source)) | |
sys.stderr.write('%s: %d/%d snippets updated\n' % | |
(file, c, snippet_count)) | |
sys.stderr.write('\nTotal: %d snippets, %d updated snippets.\n' % | |
(total_snippet_count, changed_snippets_count)) | |
sys.exit(exit_code) | |