X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=python%2Fbook_snippets.py;h=4bc4252e79da3bad9cb15876eb2f4218a4f24d2f;hb=a6a51abfd0195a3cf7d6ea095cf69808852f21ce;hp=47b683471657e39c1fcf3ef764bf2e8bbaf22075;hpb=a066a93ee74edebb9d238a1bac93c3bc7e8e6e4a;p=lilypond.git diff --git a/python/book_snippets.py b/python/book_snippets.py index 47b6834716..4bc4252e79 100644 --- a/python/book_snippets.py +++ b/python/book_snippets.py @@ -6,15 +6,14 @@ global _;_=ly._ import re import os import copy -# TODO: We are using os.popen3, which has been deprecated since python 2.6. The -# suggested replacement is the Popen function of the subprocess module. -# Unfortunately, on windows this needs the msvcrt module, which doesn't seem -# to be available in GUB?!?!?! -# from subprocess import Popen, PIPE +import shutil +import subprocess +import sys progress = ly.progress warning = ly.warning error = ly.error +debug = ly.debug_output @@ -39,7 +38,6 @@ FILENAME = 'filename' FILTER = 'filter' FRAGMENT = 'fragment' LAYOUT = 'layout' -LILYQUOTE = 'lilyquote' LINE_WIDTH = 'line-width' NOFRAGMENT = 'nofragment' NOGETTEXT = 'nogettext' @@ -108,12 +106,19 @@ snippet_options = { }, ## + # TODO: Remove the 1mm additional padding in the line-width + # once lilypond creates tighter cropped images! PAPER: { PAPERSIZE: r'''#(set-paper-size "%(papersize)s")''', INDENT: r'''indent = %(indent)s''', - LINE_WIDTH: r'''line-width = %(line-width)s''', - QUOTE: r'''line-width = %(line-width)s - 2.0 * %(exampleindent)s''', - LILYQUOTE: r'''line-width = %(line-width)s - 2.0 * %(exampleindent)s''', + LINE_WIDTH: r'''line-width = %(line-width)s + %% offset the left padding, also add 1mm as lilypond creates cropped + %% images with a little space on the right + line-width = #(- line-width (* mm %(padding_mm)f) (* mm 1))''', + QUOTE: r'''line-width = %(line-width)s - 2.0 * %(exampleindent)s + %% offset the left padding, also add 1mm as lilypond creates cropped + %% images with a little space on the right + line-width = #(- line-width (* mm %(padding_mm)f) (* mm 1))''', RAGGED_RIGHT: r'''ragged-right = ##t''', NORAGGED_RIGHT: r'''ragged-right = ##f''', }, @@ -142,6 +147,8 @@ snippet_options = { def classic_lilypond_book_compatibility (key, value): + if key == 'lilyquote': + return (QUOTE, value) if key == 'singleline' and value == None: return (RAGGED_RIGHT, None) @@ -175,7 +182,6 @@ PREAMBLE_LY = '''%%%% Generated by %(program_name)s \paper { %(paper_string)s - line-width = #(- line-width (* mm %(padding_mm)f)) } \layout { @@ -323,8 +329,10 @@ class IncludeSnippet (Snippet): class LilypondSnippet (Snippet): def __init__ (self, type, match, formatter, line_number, global_options): Snippet.__init__ (self, type, match, formatter, line_number, global_options) + self.filename = '' + self.ext = '.ly' os = match.group ('options') - self.do_options (os, self.type) + self.parse_snippet_options (os, self.type) def snippet_options (self): @@ -374,81 +382,85 @@ class LilypondSnippet (Snippet): def split_options (self, option_string): return self.formatter.split_snippet_options (option_string); - def do_options (self, option_string, type): - self.option_dict = {} + def parse_snippet_options (self, option_string, type): + self.snippet_option_dict = {} + # Split option string and create raw option_dict from it options = self.split_options (option_string) for option in options: + (key, value) = (option, None) if '=' in option: (key, value) = re.split ('\s*=\s*', option) - self.option_dict[key] = value else: - if option in no_options: - if no_options[option] in self.option_dict: - del self.option_dict[no_options[option]] + # a no... option removes a previous option if present! + if key in no_options: + if no_options[key] in self.option_dict: + del self.snippet_option_dict[no_options[key]] + key = None + # Check for deprecated options, replace them by new ones + (c_key, c_value) = classic_lilypond_book_compatibility (key, value) + if c_key: + if c_value: + warning ( + _ ("deprecated ly-option used: %s=%s") % (key, value)) + warning ( + _ ("compatibility mode translation: %s=%s") % (c_key, c_value)) else: - self.option_dict[option] = None - + warning ( + _ ("deprecated ly-option used: %s") % key) + warning ( + _ ("compatibility mode translation: %s") % c_key) + (key, value) = (c_key, c_value) + # Finally, insert the option: + if key: + self.snippet_option_dict[key] = value # If LINE_WIDTH is used without parameter, set it to default. - has_line_width = self.option_dict.has_key (LINE_WIDTH) - if has_line_width and self.option_dict[LINE_WIDTH] == None: - has_line_width = False - del self.option_dict[LINE_WIDTH] - - # TODO: Can't we do that more efficiently (built-in python func?) - for k in self.formatter.default_snippet_options: - if k not in self.option_dict: - self.option_dict[k] = self.formatter.default_snippet_options[k] - - # RELATIVE does not work without FRAGMENT; - # make RELATIVE imply FRAGMENT - has_relative = self.option_dict.has_key (RELATIVE) - if has_relative and not self.option_dict.has_key (FRAGMENT): - self.option_dict[FRAGMENT] = None - - if not has_line_width: - if type == 'lilypond' or FRAGMENT in self.option_dict: - self.option_dict[RAGGED_RIGHT] = None - - if type == 'lilypond': - if LINE_WIDTH in self.option_dict: - del self.option_dict[LINE_WIDTH] + has_line_width = self.snippet_option_dict.has_key (LINE_WIDTH) + if has_line_width and self.snippet_option_dict[LINE_WIDTH] == None: + del self.snippet_option_dict[LINE_WIDTH] + + # RELATIVE does not work without FRAGMENT, so imply that + if self.snippet_option_dict.has_key (RELATIVE): + self.snippet_option_dict[FRAGMENT] = None + + # Now get the default options from the formatter object (HTML, latex, + # texinfo, etc.) and insert the explicit snippet options to get the + # list of all options for this snippet + # first, make sure we have an INDENT value as a fallback + self.option_dict = {INDENT: '0\\mm'}; + self.option_dict.update (self.formatter.default_snippet_options); + self.option_dict.update (self.snippet_option_dict); + + # also construct a list of all options (as strings) that influence the + # visual appearance of the snippet + lst = filter (lambda (x,y): x not in PROCESSING_INDEPENDENT_OPTIONS, + self.option_dict.iteritems ()); + option_list = [] + for (key, value) in lst: + if value == None: + option_list.append (key) else: - if RAGGED_RIGHT in self.option_dict: - if LINE_WIDTH in self.option_dict: - del self.option_dict[LINE_WIDTH] - - if QUOTE in self.option_dict or type == 'lilypond': - if LINE_WIDTH in self.option_dict: - del self.option_dict[LINE_WIDTH] + option_list.append (key + "=" + value) + option_list.sort () + self.outputrelevant_option_list = option_list + #print ("self.outputrelevant_option_list: %s\n" % self.outputrelevant_option_list); - if not INDENT in self.option_dict: - self.option_dict[INDENT] = '0\\mm' # Set a default line-width if there is none. We need this, because # lilypond-book has set left-padding by default and therefore does # #(define line-width (- line-width (* 3 mm))) # TODO: Junk this ugly hack if the code gets rewritten to concatenate # all settings before writing them in the \paper block. - if not LINE_WIDTH in self.option_dict: - if not QUOTE in self.option_dict: - if not LILYQUOTE in self.option_dict: - self.option_dict[LINE_WIDTH] = "#(- paper-width \ -left-margin-default right-margin-default)" - - def get_option_list (self): - if not 'option_list' in self.__dict__: - option_list = [] - for (key, value) in self.option_dict.items (): - if value == None: - option_list.append (key) - else: - option_list.append (key + '=' + value) - option_list.sort () - self.option_list = option_list - return self.option_list + #if not LINE_WIDTH in self.option_dict: + #if not QUOTE in self.option_dict: + #self.option_dict[LINE_WIDTH] = "#(- paper-width \ +#left-margin-default right-margin-default)" + + # Get a list of all options (as string) that influence the snippet appearance + def get_outputrelevant_option_strings (self): + return self.outputrelevant_option_list def compose_ly (self, code): @@ -478,18 +490,19 @@ left-margin-default right-margin-default)" # # To set @exampleindent locally to zero, we use the @format # environment for non-quoted snippets. + # + # Update: since July 2011 we are running texinfo on a test file + # to detect the default exampleindent, so we might reintroduce + # further usage of exampleindent again. + # + # First, make sure we have some falback default value, auto-detected + # values and explicitly specified values will always override them: override[EXAMPLEINDENT] = r'0.4\in' - override[LINE_WIDTH] = '5\\in' # = texinfo_line_widths['@smallbook'] + override[LINE_WIDTH] = '5\\in' override.update (self.formatter.default_snippet_options) + override['padding_mm'] = self.global_options.padding_mm - option_list = [] - for option in self.get_option_list (): - for name in PROCESSING_INDEPENDENT_OPTIONS: - if option.startswith (name): - break - else: - option_list.append (option) - option_string = ','.join (option_list) + option_string = ','.join (self.get_outputrelevant_option_strings ()) compose_dict = {} compose_types = [NOTES, PREAMBLE, LAYOUT, PAPER] for a in compose_types: @@ -499,20 +512,6 @@ left-margin-default right-margin-default)" option_names.sort () for key in option_names: value = self.option_dict[key] - (c_key, c_value) = classic_lilypond_book_compatibility (key, value) - if c_key: - if c_value: - warning ( - _ ("deprecated ly-option used: %s=%s") % (key, value)) - warning ( - _ ("compatibility mode translation: %s=%s") % (c_key, c_value)) - else: - warning ( - _ ("deprecated ly-option used: %s") % key) - warning ( - _ ("compatibility mode translation: %s") % c_key) - - (key, value) = (c_key, c_value) if value: override[key] = value @@ -579,12 +578,8 @@ left-margin-default right-margin-default)" # code plus fragment options relevant to processing by # lilypond, not the snippet + preamble hash = md5 (self.relevant_contents (self.ly ())) - for option in self.get_option_list (): - for name in PROCESSING_INDEPENDENT_OPTIONS: - if option.startswith (name): - break - else: - hash.update (option) + for option in self.get_outputrelevant_option_strings (): + hash.update (option) ## let's not create too long names. self.checksum = hash.hexdigest ()[:10] @@ -593,7 +588,7 @@ left-margin-default right-margin-default)" def basename (self): cs = self.get_checksum () - name = '%s/lily-%s' % (cs[:2], cs[2:]) + name = os.path.join (cs[:2], 'lily-%s' % cs[2:]) return name final_basename = basename @@ -609,7 +604,7 @@ left-margin-default right-margin-default)" existing = open (filename, 'r').read () if self.relevant_contents (existing) != self.relevant_contents (self.full_ly ()): - warning ("%s: duplicate filename but different contents of orginal file,\n\ + warning ("%s: duplicate filename but different contents of original file,\n\ printing diff against existing file." % filename) ly.stderr_write (self.filter_pipe (self.full_ly (), 'diff -u %s -' % filename)) else: @@ -623,7 +618,7 @@ printing diff against existing file." % filename) def link_all_output_files (self, output_dir, output_dir_files, destination): existing, missing = self.all_output_files (output_dir, output_dir_files) if missing: - print '\nMissing', missing + error (_ ('Missing files: %s') % ', '.join (missing)) raise CompileError(self.basename()) for name in existing: if (self.global_options.use_source_file_names @@ -648,12 +643,31 @@ printing diff against existing file." % filename) dst_path = os.path.split(dst)[0] if not os.path.isdir (dst_path): os.makedirs (dst_path) - os.link (src, dst) + try: + if (self.global_options.use_source_file_names + and isinstance (self, LilypondFileSnippet)): + fout = open (dst, 'w') + fin = open (src, 'r') + for line in fin.readlines (): + fout.write (line.replace (self.basename (), self.final_basename ())) + fout.close () + fin.close () + else: + try: + os.link (src, dst) + except AttributeError: + shutil.copyfile (src, dst) + except (IOError, OSError): + error (_ ('Could not overwrite file %s') % dst) + raise CompileError(self.basename()) def additional_files_to_consider (self, base, full): return [] def additional_files_required (self, base, full): - return [] + result = []; + if self.ext != '.ly': + result.append (base + self.ext) + return result def all_output_files (self, output_dir, output_dir_files): @@ -690,6 +704,7 @@ printing diff against existing file." % filename) map (consider_file, [base + '.tex', base + '.eps', + base + '.pdf', base + '.texidoc', base + '.doctitle', base + '-systems.texi', @@ -730,13 +745,13 @@ printing diff against existing file." % filename) def filter_pipe (self, input, cmd): """Pass input through cmd, and return the result.""" - if self.global_options.verbose: - progress (_ ("Running through filter `%s'\n") % cmd) + debug (_ ("Running through filter `%s'") % cmd, True) - # TODO: Use Popen once we resolve the problem with msvcrt in Windows: - (stdin, stdout, stderr) = os.popen3 (cmd) - # p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) - # (stdin, stdout, stderr) = (p.stdin, p.stdout, p.stderr) + closefds = True + if (sys.platform == "mingw32"): + closefds = False + p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=closefds) + (stdin, stdout, stderr) = (p.stdin, p.stdout, p.stderr) stdin.write (input) status = stdin.close () @@ -757,8 +772,7 @@ printing diff against existing file." % filename) ly.stderr_write (stderr.read ()) exit (status) - if self.global_options.verbose: - progress ('\n') + debug ('\n') return output @@ -807,8 +821,8 @@ class LilypondFileSnippet (LilypondSnippet): def __init__ (self, type, match, formatter, line_number, global_options): LilypondSnippet.__init__ (self, type, match, formatter, line_number, global_options) self.filename = self.substring ('filename') - self.ext = os.path.splitext (os.path.basename (self.filename))[1] - self.contents = file (BookBase.find_file (self.filename, global_options.include_path)).read () + self.contents = file (BookBase.find_file (self.filename, + global_options.include_path, global_options.original_dir)).read () def get_snippet_code (self): return self.contents; @@ -841,6 +855,7 @@ class MusicXMLFileSnippet (LilypondFileSnippet): LilypondFileSnippet.__init__ (self, type, match, formatter, line_number, global_options) self.compressed = False self.converted_ly = None + self.ext = os.path.splitext (os.path.basename (self.filename))[1] self.musicxml_options_dict = { 'verbose': '--verbose', 'lxml': '--lxml', @@ -884,14 +899,6 @@ class MusicXMLFileSnippet (LilypondFileSnippet): return ('\\sourcefilename \"%s\"\n\\sourcefileline 0\n%s' % (name, self.converted_ly)) - def additional_files_required (self, base, full): - result = []; - if self.compressed: - result.append (base + '.mxl') - else: - result.append (base + '.xml') - return result - def write_ly (self): base = self.basename () path = os.path.join (self.global_options.lily_output_dir, base) @@ -907,7 +914,7 @@ class MusicXMLFileSnippet (LilypondFileSnippet): if os.path.exists (xmlfilename): diff_against_existing = self.filter_pipe (self.contents, 'diff -u %s - ' % xmlfilename) if diff_against_existing: - warning (_ ("%s: duplicate filename but different contents of orginal file,\n\ + warning (_ ("%s: duplicate filename but different contents of original file,\n\ printing diff against existing file.") % xmlfilename) ly.stderr_write (diff_against_existing) else: