]> git.donarmstrong.com Git - lilypond.git/commitdiff
Get texidoc translations out of snippets source files
authorJohn Mandereau <john.mandereau@gmail.com>
Tue, 10 Jul 2012 10:06:17 +0000 (12:06 +0200)
committerJohn Mandereau <john.mandereau@gmail.com>
Tue, 17 Jul 2012 15:26:26 +0000 (17:26 +0200)
Texidoc translations are inserted in .ly snippets at build stage
instead of makelsr.py run.

This simplifies overall maintenance of snippets, in particular
this avoids Git committish update headache for translators.

See final discussion at
http://lists.gnu.org/archive/html/lilypond-devel/2012-06/msg00438.html

Documentation/GNUmakefile
Documentation/contributor/doc-work.itexi
Documentation/contributor/lsr-work.itexi
Documentation/snippets/GNUmakefile
make/lilypond-vars.make
scripts/auxiliar/makelsr.py
scripts/build/makesnippets.py [new file with mode: 0644]

index c53338ca04e2beb49f98f384cca0c13ec9081681..b1c47c1f7950dbc79663ced0ba74a967b4d30b4e 100644 (file)
@@ -31,6 +31,7 @@ README_TOP_FILES= DEDICATION THANKS
 
 IN_ITELY_FILES = $(call src-wildcard,snippets/*-intro.itely)
 SNIPPET_LY_FILES = $(call src-wildcard,snippets/*.ly)
+OUT_SNIPPET_LY_FILES = $(SNIPPET_LY_FILES:%.ly=out/%.ly)
 
 EXTRA_DIST_FILES = $(call src-wildcard,*.init) $(call src-wildcard,*.bst)
 
@@ -253,7 +254,15 @@ $(outdir)/%/source:
 $(outdir)/%.itely: snippets/%-intro.itely snippets/%.snippet-list
        xargs $(LYS_TO_TELY) -f doctitle,texidoc,verbatim --name=$@ --template=$< < $(filter %.snippet-list, $^)
 
-$(outdir)/snippets.texi: $(GENERATED_ITELY_FILES) $(SNIPPET_LY_FILES)
+$(TEXI_FILES_FROM_TELY): $(GENERATED_ITELY_FILES) $(OUT_SNIPPET_LY_FILES)
+
+$(OUT_SNIPPET_LY_FILES): out/ly-snippets.dep
+
+out/ly-snippets.dep: $(SNIPPET_LY_FILES)
+       mkdir -p snippets/out
+       $(buildscript-dir)/makesnippets $(src-dir)/snippets snippets/out $(src-dir)
+       mkdir -p out
+       touch $@
 
 $(outdir)/%.bib: %.bib
        ln -f $< $@
index cdf0e26f8d518de9487f8198bc53f7c3054ad0ff..e8d993703a8f9db8b6a66351afb299c28ff0422b 100644 (file)
@@ -2003,11 +2003,6 @@ the changes it made with @command{git diff} before committing; if you
 don't do so, some @code{@@lilypond} snippets might be broken or make
 no sense in their context.
 
-When you have updated texidocs in
-@file{Documentation/@var{MY-LANGUAGE}/texidocs}, you can get these
-changes into compiled snippets in @file{Documentation/snippets}, see
-@q{General guidelines} in @ref{Adding and editing snippets}.
-
 Finally, a command runs the three update processes above for all
 enabled languages (from @file{Documentation/}):
 
@@ -2042,23 +2037,6 @@ by doing
 git rev-list HEAD |head -1
 @end example
 
-A special case is updating Snippet documentation strings in
-@file{Documentation/@var{MY-LANGUAGE}/texidocs}.  For these to be
-correctly marked as up-to-date, first run @code{makelsr.py} as
-explained in @ref{Adding and editing snippets}, and commit the
-resulting compiled snippets left in @file{Documentation/snippets/}.
-Say the SHA1 ID code of this commit is <C>.  Now edit again your
-translated files in @file{Documentation/@var{MY-LANGUAGE}/texidocs}
-adjusting the 40-digit committish that appears in the text to be <C>;
-finally, commit these updated files.  Not doing so would result in
-changes made both to your updates and original snippets to
-persistently appear in the check-translation output as if they were
-out of sync.
-
-This two-phase mechanism avoids the (practically) unsolvable problem
-of guessing what committish will have our update, and pretending to
-put this very committish on the files in the same commit.
-
 @c http://lists.gnu.org/archive/html/lilypond-devel/2009-01/msg00245.html
 @c contains a helper script which could be used to perform massive
 @c committish updates.
index be4493838a6d1de902163928d7f88ac092aaaf7c..c4dad5c28f1fcef58173e1f8f8d832ddf90842e2 100644 (file)
@@ -64,17 +64,6 @@ source tree
 scripts/auxiliar/makelsr.py
 @end example
 
-@noindent
-@command{makelsr} also copies translated texidoc fields and snippet titles into
-snippets in @file{Documentation/snippets}.  Note: this, in turn, could
-make the translated texidoc fields to appear as out of sync when you
-run @code{make check-translation}, if the originals changed from the
-last translation update, even if the translations are also updated;
-see @ref{Documentation translation maintenance} for details about
-updating the docs; in particular, see @ref{Updating translation
-committishes} to learn how to mark these translated fields as fully
-updated.
-
 Be sure that @command{make doc} runs successfully before submitting a
 patch, to prevent breaking compilation.
 
@@ -209,13 +198,26 @@ Next, download the updated snippets and run makelsr against them.
 From the top source directory, run:
 
 @smallexample
-wget http://lsr.dsi.unimi.it/download/lsr-snippets-docs-@var{YYYY-MM-DD}.tar.gz
-tar -xzf lsr-snippets-docs-@var{YYYY-MM-DD}.tar.gz
-scripts/auxiliar/makelsr.py lsr-snippets-docs-@var{YYYY-MM-DD}
+wget http://lsr.dsi.unimi.it/download/lsr-snippets-docs-`date +%F`.tar.gz
+tar -xzf lsr-snippets-docs-`date +%F`.tar.gz
+make -C $LILYPOND_BUILD_DIR
+scripts/auxiliar/makelsr.py lsr-snippets-docs-`date +%F`
 @end smallexample
 
 @noindent
-where @var{YYYY-MM-DD} is the current date, e.g. 2011-12-25.
+where @command{date +%F} gives the current date in format
+@var{YYYY-MM-DD} (the snippets archive is usually generated around
+03:50 CET, you may want to use @command{date -d yesterday +%F}
+instead, depending on your time zone and the time you run this
+commands sequence).  @command{make} is included in this sequence so
+that @command{makelsr} can run @command{lilypond} and
+@command{convert-ly} versions that match current source tree; you can
+select different binaries if desired or needed, to see options for
+this do
+
+@smallexample
+scripts/auxiliar/makelsr.py --help
+@end smallexample
 
 @item
 Follow the instructions printed on the console to manually check for
@@ -232,13 +234,13 @@ the files git is tracking.  Run @code{git status} and look
 carefully to see if files have been added.  If so, add them with
 @code{git add}.
 
-As the console says, makelsr creates a list of possibly unsafe
-files in @file{lsr-unsafe.txt} by running @code{lilypond} against each
-snippet using the @code{-dsafe} switch.  This list can be quite
-long.  However, by using the command @code{xargs git diff HEAD < lsr-unsafe.txt}
-git will take that list and check whether any of the snippets are
-different from the snippet already in master.  If any is different
-it must be checked manually VERY CAREFULLY.
+As the console says, @command{makelsr} creates a list of possibly
+unsafe files in @file{lsr-unsafe.txt} by running @code{lilypond}
+against each snippet using the @code{-dsafe} switch.  This list can be
+quite long.  However, by using the command @code{xargs git diff HEAD <
+lsr-unsafe.txt} git will take that list and check whether any of the
+snippets are different from the snippet already in master.  If any is
+different it must be checked manually VERY CAREFULLY.
 
 @warning{Somebody could sneak a @code{#'(system "rm -rf /")}
 command into our source tree if you do not do this!  Take this
index 7fccf9189cc74551f5cdc3c140b4d45f109bc4a7..cfc96feec521d4569a0fd4331001b624a4b840a5 100644 (file)
@@ -1,8 +1,14 @@
 depth = ../..
 
+.PHONY: snippets
+
 SUBDIRS = new
 EXTRA_DIST_FILES = $(call src-wildcard,*.snippet-list) \
   $(call src-wildcard,*.ly) $(call src-wildcard,*.itely) \
   README
+SNIPPET_LY_FILES = $(call src-wildcard,*.ly)
+OUT_SNIPPET_LY_FILES = $(SNIPPET_LY_FILES:%.ly=out/%.ly)
 
 include $(depth)/make/stepmake.make
+
+default:
index 57cddb16ee37c75cd6cf850deed8cf1430e3d4cb..69a863bdc89a6902482a0286e3220d4e6de1d696 100644 (file)
@@ -28,7 +28,7 @@ CONVERT_LY = $(script-dir)/convert-ly.py
 LILYPOND_BOOK = $(script-dir)/lilypond-book.py
 
 LILYPOND_BOOK_INCLUDES = -I $(src-dir)/ -I $(outdir) -I $(input-dir)   \
- -I $(top-src-dir)/Documentation -I $(top-src-dir)/Documentation/snippets \
+ -I $(top-src-dir)/Documentation -I $(top-build-dir)/Documentation/snippets/out \
  -I $(input-dir)/regression/ -I $(top-src-dir)/Documentation/included/ \
  -I $(top-build-dir)/mf/$(outconfbase)/        \
  -I $(top-build-dir)/mf/out/ \
index 6927476be928b4c249761300bc550b3959751a1e..278173f6361b288b8d7ac30e753884e3734fee4d 100755 (executable)
@@ -4,22 +4,28 @@ import sys
 import os
 import glob
 import re
+import optparse
+import tempfile
+
+lilypond_flags = "-dno-print-pages -dsafe"
+
+lys_from_lsr = os.path.join ('Documentation', 'snippets')
+new_lys = os.path.join ('Documentation', 'snippets', 'new')
+ly_output = os.path.join (tempfile.gettempdir (), 'lsrtest')
+
+# which convert-ly and lilypond to use
+P = os.path.join (os.environ.get ("LILYPOND_BUILD_DIR", ""),
+                  "out/bin/convert-ly")
+if os.path.isfile (P):
+    conv_path = os.path.dirname (P)
+elif os.path.isfile ("build/out/bin/convert-ly"):
+    conv_path = "build/out/bin/"
+else:
+    conv_path=''
+convert_ly = os.path.join (conv_path, 'convert-ly')
+lilypond_bin = os.path.join (conv_path, 'lilypond')
 
-sys.path.append ('python')
-import langdefs
-
-DEST = os.path.join ('Documentation', 'snippets')
-NEW_LYS = os.path.join ('Documentation', 'snippets', 'new')
-TEXIDOCS = [os.path.join ('Documentation', language_code, 'texidocs')
-            for language_code in langdefs.LANGDICT]
 
-USAGE = '''  Usage: makelsr.py [LSR_SNIPPETS_DIR]
-This script must be run from top of the source tree;
-it updates snippets %(DEST)s with snippets
-from %(NEW_LYS)s or LSR_SNIPPETS_DIR.
-If a snippet is present in both directories, the one
-from %(NEW_LYS)s is preferred.
-''' % vars ()
 
 LY_HEADER_LSR = '''%% DO NOT EDIT this file manually; it is automatically
 %% generated from LSR http://lsr.dsi.unimi.it
@@ -35,38 +41,141 @@ LY_HEADER_NEW = '''%% DO NOT EDIT this file manually; it is automatically
 %% and then run scripts/auxiliar/makelsr.py
 %%
 %% This file is in the public domain.
-''' % NEW_LYS
+''' % new_lys
+
+options_parser = optparse.OptionParser (
+    description = "makelsr - update snippets directory from LSR",
+    usage = '''%%prog [options] [LSR_SNIPPETS_DIR]
+Unless -s option is specified, this script must be run from top of the
+source tree. If LSR_SNIPPETS_DIR is not specified, it defaults to
+current directory.
+
+Remove snippets in TOP_SOURCE_DIR/%(lys_from_lsr)s and put in snippets
+from LSR_SNIPPETS_DIR run through convert-ly or from
+TOP_SOURCE_DIR/%(new_lys)s; if a snippet is present in both
+directories, the one from TOP_SOURCE_DIR/%(new_lys)s is preferred.
+All written snippets are copied in LY_OUTPUT
+with appending translations from .texidoc files and are tested with
+lilypond with flags %(lilypond_flags)s
+
+''' % vars ())
+
+options_parser.add_option ('-s', '--top-source',
+                           dest="top_source_dir",
+                           action="store",
+                           metavar="TOP_SOURCE_DIR",
+                           default=".",
+                           help="set LilyPond top source directory")
+
+options_parser.add_option ('-o', '--ly-output',
+                           dest="ly_output",
+                           action="store",
+                           metavar="LY_OUTPUT",
+                           default=ly_output,
+                           help="set LilyPond output files temporary directory")
+
+options_parser.add_option ('-p', '--path',
+                           dest="bin_path",
+                           action="store",
+                           metavar="LY_PATH",
+                           default=conv_path,
+                           help="directory where looking for LilyPond binaries")
+
+options_parser.add_option ('-c', '--convert-ly',
+                           dest="convert_ly",
+                           action="store",
+                           metavar="CONVERT-LY",
+                           default="LY_PATH/convert-ly",
+                           help="convert-ly binary to use")
+
+options_parser.add_option ('-l', '--lilypond-binary',
+                           dest="lilypond_bin",
+                           action="store",
+                           metavar="LILYPOND_BIN",
+                           default="LY_PATH/lilypond",
+                           help="lilypond binary to use")
+
+(options, args) = options_parser.parse_args ()
+
+if not os.path.isdir (options.top_source_dir):
+    sys.stderr.write ("Error: top source: %s: not a directory\n" % options.top_source_dir)
+    sys.exit (4)
+
+lys_from_lsr = os.path.normpath (os.path.join (options.top_source_dir, lys_from_lsr))
+new_lys = os.path.normpath (os.path.join (options.top_source_dir, new_lys))
+sys.path.append (os.path.normpath (os.path.join (options.top_source_dir, 'python')))
+import langdefs
+texidoc_dirs = [
+    os.path.normpath (os.path.join (options.top_source_dir, 'Documentation', language_code, 'texidocs'))
+    for language_code in langdefs.LANGDICT]
+
+if not os.path.isdir (lys_from_lsr):
+    sys.stderr.write ("Error: snippets path: %s: not a directory\n" % lys_from_lsr)
+    sys.exit (3)
+if not os.path.isdir (new_lys):
+    sys.stderr.write ("Error: new snippets path: %s: not a directory\n" % lys_from_lsr)
+    sys.exit (3)
+
+ly_output_ok = False
+if os.path.isdir (options.ly_output):
+    ly_output = options.ly_output
+    ly_output_ok = True
+elif os.path.exists (options.ly_output):
+    try:
+        os.unlink (options.ly_output)
+    except Exception as e:
+        sys.stderr.write ("Warning: could not delete file before creating directory: %s\n" % e)
+    else:
+        try:
+            os.makedirs (options.ly_output)
+        except Exception as e:
+            sys.stderr.write ("Warning: could not create directory: %s\n" % e)
+        else:
+            ly_output = options.ly_output
+            ly_output_ok = True
+else:
+    try:
+        os.makedirs (options.ly_output)
+    except Exception as e:
+        sys.stderr.write ("Warning: could not create directory: %s\n" % e)
+    else:
+        ly_output = options.ly_output
+        ly_output_ok = True
+if not ly_output_ok:
+    ly_output = tempfile.gettempdir ()
+    sys.stderr.write ("Warning: could not use or create directory %s, using default %s\n" % (options.ly_output, ly_output))
 
 def exit_with_usage (n=0):
-    sys.stderr.write (USAGE)
+    options_parser.print_help (sys.stderr)
     sys.exit (n)
 
-TAGS = []
-
-if len (sys.argv) >= 2:
-    in_dir = sys.argv[1]
+if len (args):
+    in_dir = args[0]
     if not (os.path.isdir (in_dir)):
-        sys.stderr.write (in_dir + ' is not a directory.\n')
-        exit (2)
-    if len (sys.argv) >= 3:
+        sys.stderr.write ("Error: %s: not a directory\n" % in_dir)
+        sys.exit (4)
+    if len (args) > 1:
         exit_with_usage (2)
-    if not (os.path.isdir (DEST) and os.path.isdir (NEW_LYS)):
-        exit_with_usage (3)
-    TAGS = os.listdir (in_dir)
 else:
-    in_dir = ''
+    in_dir = '.'
 
-# which convert-ly to use
-if os.path.isfile("out/bin/convert-ly"):
-    conv_path='out/bin/'
-elif os.path.isfile("build/out/bin/convert-ly"):
-    conv_path='build/out/bin/'
+if options.convert_ly == "LY_PATH/convert-ly":
+    convert_ly = os.path.join (options.bin_path, "convert-ly")
 else:
-    conv_path=''
-convert_ly=conv_path+'convert-ly'
-lilypond_bin=conv_path+'lilypond'
+    convert_ly = options.convert_ly
+if not os.path.exists (convert_ly):
+    sys.stderr.write ("Warning: %s: no such file\n" % convert_ly)
+    convert_ly = "convert-ly"
+if options.lilypond_bin == "LY_PATH/lilypond":
+    lilypond_bin = os.path.join (options.bin_path, "lilypond")
+else:
+    lilypond_bin = options.lilypond_bin
+if not os.path.exists (lilypond_bin):
+    sys.stderr.write ("Warning: %s: no such file\n" % lilypond_bin)
+    lilypond_bin = "lilypond"
+sys.stderr.write ("Using %s, %s\n" % (convert_ly, lilypond_bin))
 
-print 'using '+convert_ly
+tags = os.listdir (in_dir)
 
 unsafe = []
 unconverted = []
@@ -93,6 +202,7 @@ lsr_comment_re = re.compile (r'\s*%+\s*LSR.*')
 begin_header_re = re.compile (r'\\header\s*{', re.M)
 ly_new_version_re = re.compile (r'\\version\s*"(.+?)"')
 strip_white_spaces_re = re.compile (r'[ \t]+(?=\n)')
+final_empty_lines_re = re.compile (r'\n{2,}$')
 
 # add tags to ly files from LSR
 def add_tags (ly_code, tags):
@@ -104,32 +214,15 @@ def add_version (ly_code):
     return '''%% Note: this file works from version ''' + \
         ly_new_version_re.search (ly_code).group (1) + '\n'
 
-s = 'Translation of GIT [Cc]ommittish'
-texidoc_chunk_re = re.compile (r'^(?:%+\s*' + s + \
-    r'.+)?\s*(?:texidoc|doctitle)([a-zA-Z]{2,4})\s+=(?:.|\n)*?(?=%+\s*' + \
-    s + r'|\n\} % begin verbatim|\n  (?:doctitle|texidoc|lsrtags) |$(?!.|\n))', re.M)
-
-def update_translated_texidoc (m, snippet_path, visited_languages):
-    base = os.path.splitext (os.path.basename (snippet_path))[0]
-    language_code = m.group (1)
-    visited_languages.append (language_code)
-    texidoc_path = os.path.join ('Documentation', language_code,
-                                 'texidocs', base + '.texidoc')
-    if os.path.isfile (texidoc_path):
-        return open (texidoc_path).read ()
-    else:
-        return m.group (0)
-
 def escape_backslashes_in_header(snippet):
     # ASSUME: the \header exists.
     header_char_number_start = snippet.find('\header {')
     header_char_number_end = snippet.find('} % begin verbatim')
 
     header = snippet[header_char_number_start:header_char_number_end]
-    # two levels of escaping happening here -- 4\ means 1\
-    # and the 10\ means two \ backslashes (that's 8\ ), and
-    # one backreference to group 1 (that's two 2\ ).
-    new_header = re.sub("@code\{\\\\([a-zA-Z])", "@code{\\\\\\\\\\1", header)
+    # only one level of escaping happening here
+    # thanks to raw strings
+    new_header = re.sub(r"@code\{\\([a-zA-Z])", r"@code{\\\\\1", header)
     escaped_snippet = (snippet[:header_char_number_start] +
         new_header + snippet[header_char_number_end:])
     return escaped_snippet
@@ -137,50 +230,43 @@ def escape_backslashes_in_header(snippet):
 def copy_ly (srcdir, name, tags):
     global unsafe
     global unconverted
-    dest = os.path.join (DEST, name)
+    dest = os.path.join (lys_from_lsr, name)
     tags = ', '.join (tags)
-    s = open (os.path.join (srcdir, name)).read ()
-    sys.stderr.write ('\nmakelsr.py: reading ' + os.path.join (srcdir, name) + '\n')
-
-    for path in TEXIDOCS:
-        texidoc_translation_path = \
-            os.path.join (path, os.path.splitext (name)[0] + '.texidoc')
-        if os.path.exists (texidoc_translation_path):
-            texidoc_translation = open (texidoc_translation_path).read ()
-            # Since we want to insert the translations verbatim using a 
-            # regexp, \\ is understood as ONE escaped backslash. So we have
-            # to escape those backslashes once more...
-            texidoc_translation = texidoc_translation.replace ('\\', '\\\\')
-            s = begin_header_re.sub ('\\g<0>\n' + texidoc_translation, s, 1)
+    file_path = os.path.join (srcdir, name)
+    sys.stderr.write ("\nmakelsr.py: reading %s\n" % file_path)
+    s = open (file_path).read ()
 
     s = doctitle_re.sub (doctitle_sub, s)
-    if in_dir and in_dir in srcdir:
-        s = LY_HEADER_LSR + add_tags (s, tags)
-    else:
+    if "new" in srcdir:
         s = LY_HEADER_NEW + add_version (s) + s
+    else:
+        s = LY_HEADER_LSR + add_tags (s, tags)
 
     s = mark_verbatim_section (s)
     s = lsr_comment_re.sub ('', s)
     s = strip_white_spaces_re.sub ('', s)
+    s = final_empty_lines_re.sub ('\n', s)
     s = escape_backslashes_in_header (s)
+    sys.stderr.write ("makelsr.py: writing %s\n" % dest)
     open (dest, 'w').write (s)
-    sys.stderr.write ('makelsr.py: writing ' + dest + '\n')
 
     e = os.system (convert_ly+(" -d -e '%s'" % dest))
     if e:
         unconverted.append (dest)
     if os.path.exists (dest + '~'):
         os.remove (dest + '~')
-    # no need to check snippets from input/new
-    if in_dir and in_dir in srcdir:
-        e = os.system ("%s -dno-print-pages -dsafe -o /tmp/lsrtest '%s'" %(lilypond_bin, dest))
+    # no need to check snippets from Documentation/snippets/new
+    if not "new" in srcdir:
+        e = os.system (
+            "%s %s -o %s '%s'" %
+            (lilypond_bin, lilypond_flags, ly_output, dest))
         if e:
             unsafe.append (dest)
 
 def read_source_with_dirs (src):
     s = {}
     l = {}
-    for tag in TAGS:
+    for tag in tags:
         srcdir = os.path.join (src, tag)
         l[tag] = set (map (os.path.basename,
                            glob.glob (os.path.join (srcdir, '*.ly'))))
@@ -196,14 +282,14 @@ tags_re = re.compile ('lsrtags\\s*=\\s*"(.+?)"')
 
 def read_source (src):
     s = {}
-    l = dict ([(tag, set()) for tag in TAGS])
+    l = dict ([(tag, set()) for tag in tags])
     for f in glob.glob (os.path.join (src, '*.ly')):
         basename = os.path.basename (f)
         m = tags_re.search (open (f, 'r').read ())
         if m:
             file_tags = [tag.strip() for tag in m.group (1). split(',')]
             s[basename] = (src, file_tags)
-            [l[tag].add (basename) for tag in file_tags if tag in TAGS]
+            [l[tag].add (basename) for tag in file_tags if tag in tags]
         else:
             notags_files.append (f)
     return s, l
@@ -219,62 +305,23 @@ def dump_file_list (file, file_list, update=False):
     f = open (file, 'w')
     f.write ('\n'.join (sorted (new_list)) + '\n')
 
-def update_ly_in_place (snippet_path):
-    visited_languages = []
-    contents = open (snippet_path).read ()
-    contents = texidoc_chunk_re.sub \
-        (lambda m: update_translated_texidoc (m,
-                                              snippet_path,
-                                              visited_languages),
-         contents)
-    need_line_break_workaround = False
-    for language_code in langdefs.LANGDICT:
-        if not language_code in visited_languages:
-            base = os.path.splitext (os.path.basename (snippet_path))[0]
-            texidoc_path = os.path.join ('Documentation', language_code,
-                         'texidocs', base + '.texidoc')
-            if os.path.isfile (texidoc_path):
-                texidoc_translation = open (texidoc_path).read ()
-                texidoc_translation = texidoc_translation.replace ('\\', '\\\\')
-                contents = begin_header_re.sub ('\\g<0>\n' + texidoc_translation, contents, 1)
-        else:
-            need_line_break_workaround = True
-    contents = doctitle_re.sub (doctitle_sub, contents)
-    contents = escape_backslashes_in_header (contents)
-
-    # workaround for a bug in the regex's that I'm not smart
-    # enough to figure out.  -gp
-    if need_line_break_workaround:
-        first_translated = contents.find('%% Translation of')
-        keep = contents[:first_translated+5]
-        contents = keep + contents[first_translated+5:].replace('%% Translation of', '\n%% Translation of')
-
-    open (snippet_path, 'w').write (contents)
-
-if in_dir:
-    ## clean out existing lys and generated files
-    map (os.remove, glob.glob (os.path.join (DEST, '*.ly')) +
-         glob.glob (os.path.join (DEST, '*.snippet-list')))
-
-    # read LSR source where tags are defined by subdirs
-    snippets, tag_lists = read_source_with_dirs (in_dir)
-
-    # read input/new where tags are directly defined
-    s, l = read_source (NEW_LYS)
-    snippets.update (s)
-    for t in TAGS:
-        tag_lists[t].update (l[t])
-else:
-    snippets, tag_lists = read_source (NEW_LYS)
-    ## update texidocs of snippets that don't come from NEW_LYS
-    for snippet_path in glob.glob (os.path.join (DEST, '*.ly')):
-        if not os.path.basename (snippet_path) in snippets:
-            update_ly_in_place (snippet_path)
+## clean out existing lys and generated files
+map (os.remove, glob.glob (os.path.join (lys_from_lsr, '*.ly')) +
+     glob.glob (os.path.join (lys_from_lsr, '*.snippet-list')))
+
+# read LSR source where tags are defined by subdirs
+snippets, tag_lists = read_source_with_dirs (in_dir)
+
+# read input/new where tags are directly defined
+s, l = read_source (new_lys)
+snippets.update (s)
+for t in tags:
+    tag_lists[t].update (l[t])
 
 for (name, (srcdir, tags)) in snippets.items ():
     copy_ly (srcdir, name, tags)
 for (tag, file_set) in tag_lists.items ():
-    dump_file_list (os.path.join (DEST, tag + '.snippet-list'),
+    dump_file_list (os.path.join (lys_from_lsr, tag + '.snippet-list'),
                     file_set, update=not(in_dir))
 if unconverted:
     sys.stderr.write ('These files could not be converted successfully by convert-ly:\n')
@@ -287,7 +334,7 @@ if unsafe:
     sys.stderr.write ('''
 
 Unsafe files printed in lsr-unsafe.txt: CHECK MANUALLY!
-  git add %s/*.ly
+  git add %(lys_from_lsr)s/*.ly
   xargs git diff HEAD < lsr-unsafe.txt
 
-''' % DEST)
+''' % vars ())
diff --git a/scripts/build/makesnippets.py b/scripts/build/makesnippets.py
new file mode 100644 (file)
index 0000000..9e7c5a6
--- /dev/null
@@ -0,0 +1,37 @@
+#!@PYTHON@
+# makesnippets.py
+
+'''USAGE: makesnippets.py INPUT_DIR OUTPUT_DIR DOC_DIR
+
+Read all .ly files from INPUT_DIR, insert translations from .texidoc
+files found in DOC_DIR/LANG/texdiocs, and write ther result to OUTPUT_DIR.'''
+
+import glob
+import sys
+import os.path
+import re
+
+import langdefs
+
+(input_dir, output_dir, doc_dir) = sys.argv[1:4]
+
+texidoc_dirs = [os.path.join (doc_dir, language_code, 'texidocs')
+                for language_code in langdefs.LANGDICT]
+
+begin_header_re = re.compile (r'\\header\s*{', re.M)
+
+for f in glob.glob (os.path.join (input_dir, '*.ly')):
+    name = os.path.basename (f)
+    s = open (f).read ()
+    for path in texidoc_dirs:
+        texidoc_translation_path = \
+            os.path.join (path, os.path.splitext (name)[0] + '.texidoc')
+        if os.path.exists (texidoc_translation_path):
+            texidoc_translation = open (texidoc_translation_path).read ()
+            # Since we want to insert the translations verbatim using a
+            # regexp, \\ is understood as ONE escaped backslash. So we have
+            # to escape those backslashes once more...
+            texidoc_translation = texidoc_translation.replace ('\\', '\\\\')
+            s = begin_header_re.sub ('\\g<0>\n' + texidoc_translation, s, 1)
+    dest = os.path.join (output_dir, name)
+    open (dest, 'w').write (s)