1 # -*- coding: utf-8 -*-
4 # This file is part of LyX, the document processor.
5 # Licence details can be found in the file COPYING.
7 # \author Thibaut Cuvelier
9 # Full author contact details are available in file CREDITS
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
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!
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()
34 def copy_docbook(args):
37 print('Exactly four arguments are expected, only %s found: %s.' % (len(args), args))
40 # Parse the command line.
41 lilypond_command = args[1]
45 has_lilypond = lilypond_command != "" and lilypond_command != "none"
47 # Guess the path for LilyPond.
48 lilypond_folder = os.path.split(lilypond_command)[0] if has_lilypond else ''
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)
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)
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:
71 if "language='lilypond'" in line:
73 # print(re.match('<programlisting\\s+language=\'lilypond\'.*?(role=\'(?P<options>.*?)\')?>', line))
75 '<programlisting\\s+language=\'lilypond\'.*?(role=\'(?P<options>.*?)\')?>',
76 '<programlisting language="lilypond" role="\\g<options>">',
82 # shutil.move(in_file, in_lily_file)
84 # Add LilyPond to the PATH.
85 if os.path.isdir(lilypond_folder):
86 os.environ['PATH'] += os.pathsep + lilypond_folder
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
92 if os.system(command_raw) == 0:
93 print("Success running LilyPond:")
96 if os.system(command_python) == 0:
97 print("Success running LilyPond:")
100 print('Error from LilyPond')
103 # Now, in_file should have the LilyPond-processed contents.
105 # Perform the final copy.
106 shutil.copyfile(in_file, out_file, follow_symlinks=False)
109 if __name__ == '__main__':
110 copy_docbook(sys.argv)