mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-25 19:07:45 +00:00
DocBook copy: large refactoring to improve readability.
This commit is contained in:
parent
e22f52e731
commit
a464915f58
BIN
autotests/export/docbook/ff/lily-3ed27d76.png
Normal file
BIN
autotests/export/docbook/ff/lily-3ed27d76.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
@ -26,51 +26,46 @@ import shutil
|
||||
import sys
|
||||
|
||||
|
||||
def need_lilypond(file):
|
||||
# Really tailored to the kind of output lilypond.module makes (in lib/layouts).
|
||||
with open(file, 'r') as f:
|
||||
return "language='lilypond'" in f.read()
|
||||
class DocBookCopier:
|
||||
def __init__(self, args):
|
||||
|
||||
# Parse the command line.
|
||||
self.lilypond_command = args[1]
|
||||
self.in_file = args[2]
|
||||
self.out_file = args[3]
|
||||
|
||||
def copy_docbook(args):
|
||||
if len(args) != 4:
|
||||
print('Exactly four arguments are expected, only %s found: %s.' % (len(args), args))
|
||||
sys.exit(1)
|
||||
# Compute a few things from the raw parameters.
|
||||
self.in_folder = os.path.split(self.in_file)[0]
|
||||
self.out_folder = os.path.split(self.out_file)[0]
|
||||
|
||||
# Parse the command line.
|
||||
lilypond_command = args[1]
|
||||
in_file = args[2]
|
||||
out_file = args[3]
|
||||
self.in_lily_file = self.in_file.replace('.xml', '.lyxml')
|
||||
self.has_lilypond = self.lilypond_command not in {'', 'none'}
|
||||
self.lilypond_folder = os.path.split(self.lilypond_command)[0] if self.has_lilypond else ''
|
||||
self.do_lilypond_processing = self.has_lilypond and self.in_file_needs_lilypond()
|
||||
|
||||
has_lilypond = lilypond_command not in {'', 'none'}
|
||||
in_folder = os.path.split(in_file)[0]
|
||||
# Help debugging.
|
||||
print('>> Given arguments:')
|
||||
print('>> LilyPond: ' + ('present' if self.has_lilypond else 'not found') + '.')
|
||||
print('>> LilyPond callable as: ' + self.lilypond_command + '.')
|
||||
print('>> LilyPond path: ' + self.lilypond_folder + '.')
|
||||
print('>> Input file: ' + self.in_file + '.')
|
||||
print('>> Output file: ' + self.out_file + '.')
|
||||
print('>> Input folder: ' + self.in_folder + '.')
|
||||
print('>> Output folder: ' + self.out_folder + '.')
|
||||
|
||||
# Guess the path for LilyPond.
|
||||
lilypond_folder = os.path.split(lilypond_command)[0] if has_lilypond else ''
|
||||
|
||||
# Help debugging.
|
||||
print('>> Given arguments:')
|
||||
print('>> LilyPond: ' + ('present' if has_lilypond else 'not found') + '.')
|
||||
print('>> LilyPond callable as: ' + lilypond_command + '.')
|
||||
print('>> LilyPond path: ' + lilypond_folder + '.')
|
||||
print('>> Input file: ' + in_file + '.')
|
||||
print('>> Input folder: ' + in_folder + '.')
|
||||
print('>> Output file: ' + out_file + '.')
|
||||
|
||||
# Apply LilyPond to the original file if available and needed.
|
||||
if has_lilypond and need_lilypond(in_file):
|
||||
in_lily_file = in_file.replace(".xml", ".lyxml")
|
||||
print('>> The input file needs a LilyPond pass and LilyPond is available.')
|
||||
print('>> Rewriting ' + in_file)
|
||||
print('>> as ' + in_lily_file + '.')
|
||||
def in_file_needs_lilypond(self):
|
||||
# Really tailored to the kind of output lilypond.module makes (in lib/layouts).
|
||||
with open(self.in_file, 'r') as f:
|
||||
return "language='lilypond'" in f.read()
|
||||
|
||||
def preprocess_input_for_lilypond(self):
|
||||
# LilyPond requires that its input file has the .lyxml extension. Due to a bug in LilyPond,
|
||||
# use " instead of ' to encode XML attributes.
|
||||
# https://lists.gnu.org/archive/html/bug-lilypond/2021-09/msg00039.html
|
||||
# Typical transformation:
|
||||
# FROM: language='lilypond' role='fragment verbatim staffsize=16 ragged-right relative=2'
|
||||
# TO: language="lilypond" role="fragment verbatim staffsize=16 ragged-right relative=2"
|
||||
with open(in_file, 'r', encoding='utf-8') as f, open(in_lily_file, 'w', encoding='utf-8') as f_lily:
|
||||
with open(self.in_file, 'r', encoding='utf-8') as f, open(self.in_lily_file, 'w', encoding='utf-8') as f_lily:
|
||||
for line in f:
|
||||
if "language='lilypond'" in line:
|
||||
line = re.sub(
|
||||
@ -79,50 +74,94 @@ def copy_docbook(args):
|
||||
line
|
||||
)
|
||||
f_lily.write(line)
|
||||
os.unlink(in_file)
|
||||
os.unlink(self.in_file)
|
||||
|
||||
def postprocess_output_for_lilypond(self):
|
||||
# TODO.
|
||||
pass
|
||||
|
||||
def call_lilypond(self):
|
||||
# LilyPond requires that its input file has the .lyxml extension (plus bugs in LilyPond).
|
||||
print('>> Rewriting ' + self.in_file)
|
||||
print('>> as ' + self.in_lily_file + '.')
|
||||
self.preprocess_input_for_lilypond()
|
||||
|
||||
# Add LilyPond to the PATH. lilypond-book uses a direct call to lilypond from the PATH.
|
||||
if os.path.isdir(lilypond_folder):
|
||||
os.environ['PATH'] += os.pathsep + lilypond_folder
|
||||
if os.path.isdir(self.lilypond_folder):
|
||||
os.environ['PATH'] += os.pathsep + self.lilypond_folder
|
||||
|
||||
# Make LilyPond believe it is working from the temporary LyX directory. Otherwise, it tries to find files
|
||||
# starting from LyX's working directory...
|
||||
os.chdir(in_folder)
|
||||
# starting from LyX's working directory... LilyPond bug.
|
||||
os.chdir(self.in_folder)
|
||||
|
||||
# Start LilyPond on the copied file. First test the binary, then check if adding Python helps.
|
||||
command_args = ['--format=docbook', '--output=' + in_folder, in_lily_file]
|
||||
command_raw = [lilypond_command] + command_args
|
||||
command_python = ['python', lilypond_command] + command_args
|
||||
command_args = ['--format=docbook', '--output=' + self.in_folder, self.in_lily_file]
|
||||
command_raw = [self.lilypond_command] + command_args
|
||||
command_python = ['python', self.lilypond_command] + command_args
|
||||
|
||||
print('>> Running LilyPond.')
|
||||
sys.stdout.flush() # So that the LilyPond output is at the right place in the logs.
|
||||
|
||||
failed = False
|
||||
try:
|
||||
subprocess.check_call(command_raw, stdout=sys.stdout.fileno(), stderr=sys.stdout.fileno())
|
||||
print('>> Success running LilyPond with ')
|
||||
print('>> ' + str(command_raw))
|
||||
except (subprocess.CalledProcessError, OSError) as e1:
|
||||
failed = True
|
||||
exceptions = []
|
||||
for cmd in [command_raw, command_python]:
|
||||
try:
|
||||
subprocess.check_call(command_python, stdout=sys.stdout.fileno(), stderr=sys.stdout.fileno())
|
||||
subprocess.check_call(cmd, stdout=sys.stdout.fileno(), stderr=sys.stdout.fileno())
|
||||
print('>> Success running LilyPond with ')
|
||||
print('>> ' + str(command_python) + '.')
|
||||
except (subprocess.CalledProcessError, OSError) as e2:
|
||||
print('>> Error from LilyPond. The successive calls were:')
|
||||
print('>> (1) Error from trying ' + str(command_raw) + ':')
|
||||
print('>> (1) ' + str(e1))
|
||||
print('>> (2) Error from trying ' + str(command_python) + ':')
|
||||
print('>> (2) ' + str(e2))
|
||||
failed = True
|
||||
print('>> ' + str(cmd))
|
||||
failed = False
|
||||
except (subprocess.CalledProcessError, OSError) as e:
|
||||
exceptions.append((cmd, e))
|
||||
|
||||
if failed:
|
||||
print('>> Error from LilyPond. The successive calls were:')
|
||||
for (i, pair) in enumerate(exceptions):
|
||||
exc = pair[0]
|
||||
cmd = pair[1]
|
||||
|
||||
print('>> (' + i + ') Error from trying ' + str(cmd) + ':')
|
||||
print('>> (' + i + ') ' + str(exc))
|
||||
|
||||
if failed:
|
||||
sys.exit(1)
|
||||
|
||||
# Now, in_file should have the LilyPond-processed contents.
|
||||
# LilyPond has a distressing tendency to leave the raw LilyPond code in the new file.
|
||||
self.postprocess_output_for_lilypond()
|
||||
|
||||
# Perform the final copy.
|
||||
shutil.copyfile(in_file, out_file, follow_symlinks=False)
|
||||
def copy_lilypond_generated_images(self):
|
||||
# LilyPond generates a lot of files in LyX' temporary folder, within the ff folder: source LilyPond files
|
||||
# for each snippet to render, images in several formats.
|
||||
in_generated_images_folder = os.path.join(self.in_folder, 'ff')
|
||||
out_generated_images_folder = os.path.join(self.out_folder, 'ff')
|
||||
|
||||
os.mkdir(out_generated_images_folder)
|
||||
|
||||
for img in os.listdir(in_generated_images_folder):
|
||||
if not img.endswith('.png') and not img.endswith('.pdf'):
|
||||
continue
|
||||
|
||||
shutil.copyfile(
|
||||
os.path.join(in_generated_images_folder, img),
|
||||
os.path.join(out_generated_images_folder, img),
|
||||
follow_symlinks=False,
|
||||
)
|
||||
|
||||
def copy(self):
|
||||
# Apply LilyPond to the original file if available and needed.
|
||||
if self.do_lilypond_processing:
|
||||
print('>> The input file needs a LilyPond pass and LilyPond is available.')
|
||||
self.call_lilypond()
|
||||
|
||||
# Perform the actual copy: both the modified XML file and the generated images, if LilyPond is used.
|
||||
shutil.copyfile(self.in_file, self.out_file, follow_symlinks=False)
|
||||
if self.do_lilypond_processing:
|
||||
self.copy_lilypond_generated_images()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
copy_docbook(sys.argv)
|
||||
if len(sys.argv) != 4:
|
||||
print('Exactly four arguments are expected, only %s found: %s.' % (len(sys.argv), sys.argv))
|
||||
sys.exit(1)
|
||||
|
||||
DocBookCopier(sys.argv).copy()
|
||||
|
Loading…
Reference in New Issue
Block a user