def _get_feed_data_dir(self): d = os.path.join(self._framework.plugins['vars'].vars['intermediate_data_dir'], "StillWeb.FeedGenerator") # Quietly make sure the directory exists ensure_path(d) return d
def math_placeholder(self, latex_code, force_img=False): # Strip whitespace latex_code = latex_code.strip() # If the code is empty, don't do anything. if not latex_code: raise ReplaceWithNothing() # Find the texvc executable texvc_program_dir = self._framework.plugins['vars'].vars['texvc_program_dir'] # Find the output directory (output_dir_url, output_dir) = self._get_texvc_outdir() intermediate_dir = self._get_my_intermediate_dir() # Quietly make sure both directories exist ensure_path(output_dir) ensure_path(intermediate_dir) # Create a Texvc instance texvc = Texvc(texvc_program_dir, output_dir) # Two MD5 sums are calculated: # 1. The "original" checksum of the code actually found in the page # 2. The "canonical" checksum that texvc generates # These might be identical, or they might be different. We cache them both. orig_md5 = hashlib.md5(latex_code.encode('UTF-8')).hexdigest() orig_md5_filename = os.path.join(intermediate_dir, "texvc-original-%s-sum" % (orig_md5,)) # Try to read the canonical MD5 sum from the cache file. Generate it if it's not cached. try: f = open(orig_md5_filename, "rt") canonical_md5 = binascii.b2a_hex(binascii.a2b_hex(f.read().strip().encode('ascii'))).decode('ascii') # make sure it's hexadecimal assert len(canonical_md5) == 32 # 32 hexadecimal digits f.close() except EnvironmentError as exc: if exc.errno != errno.ENOENT: raise # Generate the MD5 sum of the *canonical* code (i.e. of texvc_tex's output) canonical_md5 = texvc.hash_code(latex_code).hexdigest() # Cache the generated MD5 sum for future reference f = open(orig_md5_filename, "wt", encoding="UTF-8") f.write(canonical_md5) f.close() # Check if we've already generated the output stamp_filename = os.path.join(intermediate_dir, "texvc-canonical-%s-stamp" % (canonical_md5,)) result_filename = os.path.join(intermediate_dir, "texvc-canonical-%s-result" % (canonical_md5,)) output_basename = "%s.png" % (canonical_md5,) output_filename = os.path.join(output_dir, output_basename) output_url = rfc3986_urljoin(output_dir_url, output_basename) if os.path.exists(stamp_filename) and os.path.exists(output_filename): print("skipping TeX %s" % (output_filename,)) # Use the cached result result = pickle.load(open(result_filename, "rb")) # Check the hash result - this should never fail unless the cache file is corrupt if result['md5'] != canonical_md5: raise AssertionError("corrupt file: %r" % (result_filename,)) else: print("generating TeX %s" % (output_filename,)) # Parse texvc result and check for errors result = texvc.run_texvc(latex_code) # Check the hash result - our caching here breaks if we get this wrong. if result['md5'] != canonical_md5: raise AssertionError("texvc md5 sum mismatch (code=%r, my_md5=%r, texvc_md5=%r)" % ( latex_code, canonical_md5, result['md5'])) # Check that the output file was created if not os.path.exists(output_filename): raise TexvcRuntimeError("texvc didn't create output file %r (canonical_md5=%r, code=%r)" % (output_filename, canonical_md5, latex_code)) # Save the result for future use pickle.dump(result, open(result_filename, "wb")) # Write the canonical MD5 sum to the timestamp file (and update its timestamp) open(stamp_filename, "ab").close() os.utime(stamp_filename, None) # should be unnecessary if we're writing to the file # If texvc gave us some HTML code (of moderate or conservative strictness), use that. if not force_img and result['html'] is not None and result['html_strictness'] > 0: raise ReplaceWithHTML(result['html']) # TODO - MathML support can go here if we want it. # Fall-back on the PNG image. imgElement = minidom.parseString("<img/>").documentElement imgElement.setAttribute('class', 'tex') imgElement.setAttribute('src', output_url) imgElement.setAttribute('alt', latex_code) raise ReplaceWithNode(imgElement)