]> git.lyx.org Git - lyx.git/blob - lib/scripts/docbook_copy.py
DocBook: work around bug in LilyPond.
[lyx.git] / lib / scripts / docbook_copy.py
1 # -*- coding: utf-8 -*-
2
3 # file docbook_copy.py
4 # This file is part of LyX, the document processor.
5 # Licence details can be found in the file COPYING.
6 #
7 # \author Thibaut Cuvelier
8 #
9 # Full author contact details are available in file CREDITS
10
11 # Usage:
12 #   python docbook_copy.py lilypond_book_command in.docbook out.docbook
13 # This script copies the original DocBook file (directly produced by LyX) to the output DocBook file,
14 # potentially applying a post-processing step. For now, the only implemented post-processing step is
15 # LilyPond.
16 # lilypond_book_command is either directly the binary to call OR the equivalent Python script that is
17 # not directly executable.
18 # /!\ The original file may be modified by this script!
19
20
21 import os
22 import os.path
23 import re
24 import shutil
25 import sys
26
27
28 def need_lilypond(file):
29     # Really tailored to the kind of output lilypond.module makes (in lib/layouts).
30     with open(file, 'r') as f:
31         return "language='lilypond'" in f.read()
32
33
34 def copy_docbook(args):
35     print(args)
36     if len(args) != 4:
37         print('Exactly four arguments are expected, only %s found: %s.' % (len(args), args))
38         sys.exit(1)
39
40     # Parse the command line.
41     lilypond_command = args[1]
42     in_file = args[2]
43     out_file = args[3]
44
45     has_lilypond = lilypond_command != "" and lilypond_command != "none"
46
47     # Guess the path for LilyPond.
48     lilypond_folder = os.path.split(lilypond_command)[0] if has_lilypond else ''
49
50     # Help debugging.
51     print("Given arguments:")
52     print("LilyPond: " + ("present" if has_lilypond else "not found") + " " + lilypond_command)
53     print("LilyPond path: " + lilypond_folder)
54     print("Input file: " + in_file)
55     print("Output file: " + out_file)
56
57     # Apply LilyPond to the original file if available and needed.
58     if has_lilypond and need_lilypond(in_file):
59         in_lily_file = in_file.replace(".xml", ".lyxml")
60         print("The input file needs a LilyPond pass and LilyPond is available.")
61         print("Rewriting " + in_file + " as " + in_lily_file)
62
63         # LilyPond requires that its input file has the .lyxml extension. Due to a bug in LilyPond,
64         # use " instead of ' to encode XML attributes.
65         # https://lists.gnu.org/archive/html/bug-lilypond/2021-09/msg00039.html
66         # Typical transformation:
67         #     FROM:  language='lilypond' role='fragment verbatim staffsize=16 ragged-right relative=2'
68         #     TO:    language="lilypond" role="fragment verbatim staffsize=16 ragged-right relative=2"
69         with open(in_file, 'r', encoding='utf-8') as f, open(in_lily_file, 'w', encoding='utf-8') as f_lily:
70             for line in f:
71                 if "language='lilypond'" in line:
72                     # print(line)
73                     # print(re.match('<programlisting\\s+language=\'lilypond\'.*?(role=\'(?P<options>.*?)\')?>', line))
74                     line = re.sub(
75                         '<programlisting\\s+language=\'lilypond\'.*?(role=\'(?P<options>.*?)\')?>',
76                         '<programlisting language="lilypond" role="\\g<options>">',
77                         line
78                     )
79                     # print(line)
80                 f_lily.write(line)
81         os.unlink(in_file)
82         # shutil.move(in_file, in_lily_file)
83
84         # Add LilyPond to the PATH.
85         if os.path.isdir(lilypond_folder):
86             os.environ['PATH'] += os.pathsep + lilypond_folder
87
88         # Start LilyPond on the copied file. First test the binary, then check if adding Python helps.
89         command_raw = lilypond_command + ' --format=docbook ' + in_lily_file
90         command_python = 'python -tt "' + lilypond_command + '" --format=docbook ' + in_lily_file
91
92         if os.system(command_raw) == 0:
93             print("Success running LilyPond:")
94             print(command_raw)
95         else:
96             if os.system(command_python) == 0:
97                 print("Success running LilyPond:")
98                 print(command_python)
99             else:
100                 print('Error from LilyPond')
101                 sys.exit(1)
102
103         # Now, in_file should have the LilyPond-processed contents.
104
105     # Perform the final copy.
106     shutil.copyfile(in_file, out_file, follow_symlinks=False)
107
108
109 if __name__ == '__main__':
110     copy_docbook(sys.argv)