require "open3" require "rbconfig" require "tempfile" require "yaml" module Mn2pdf MN2PDF_JAR_PATH = File.join(File.dirname(__FILE__), "../bin/mn2pdf.jar") DEFAULT_JAVA_OPTS = %w[-Xss10m -Xmx3g -Djava.awt.headless=true].freeze FONTS_MANIFEST = :font_manifest def self.jvm_options options = DEFAULT_JAVA_OPTS.dup if RbConfig::CONFIG["host_os"].match?(/darwin|mac os/) options << "-Dapple.awt.UIElement=true" end options << "-Duser.home=#{Dir.home}" options end def self.help cmd = ["java", *jvm_options, "-jar", MN2PDF_JAR_PATH].join(" ") # help message goes to STDERR (from mn2pdf v1.36) _, help_message, = Open3.capture3(cmd) help_message end def self.version cmd = ["java", *jvm_options, "-jar", MN2PDF_JAR_PATH, "-v"].join(" ") message, = Open3.capture3(cmd) message.strip end def self.convert(url_path, output_path, xsl_stylesheet, options = {}) cmd = build_cmd(url_path, output_path, xsl_stylesheet) return unless cmd case options when String mn2pdf(cmd + [options]) when Hash mn2pdf_hash(cmd, options) else warn "Unsupported options type #{options.class}" end end def self.build_cmd(url, output, xslt) return if url.nil? || output.nil? || xslt.nil? ["java", *jvm_options, "-jar", MN2PDF_JAR_PATH, "--xml-file", quote(url), "--xsl-file", quote(xslt), "--pdf-file", quote(output)] end def self.mn2pdf_hash(cmd, options) manifest = options.delete(FONTS_MANIFEST) options_to_cmd(options, cmd) if manifest dump_fontist_manifest_locations(manifest) do |manifest_path| cmd << "--font-manifest" << quote(manifest_path) mn2pdf(cmd) end else mn2pdf(cmd) end end def self.mn2pdf(cmd) cmd = cmd.join(" ") puts cmd stdout, stderr, status = Open3.capture3(cmd) unless status.success? puts_error_log(stdout, stderr) raise StandardError.new("mn2pdf failed! #{parse_error_msg(stderr)}") end end def self.puts_error_log(stdout, stderr) puts ["Fatal error!", "STDOUT:", stdout.strip, "STDERR:", stderr.strip] .join("\n") .split("\n") .map { |line| "[mn2pdf] #{line}" } .join("\n") end def self.parse_error_msg(stderr) err = stderr.split("\n").detect { |line| line.start_with? "Error: " } err ? err[7..-1] : stderr.strip end def self.quote(str) return "" if str.nil? || str.empty? return str if /^'.*'$/.match(str) || /^".*"$/.match(str) %("#{str}") end def self.dump_fontist_manifest_locations(manifest) Tempfile.create(["fontist_locations", ".yml"]) do |f| f.write manifest.to_yaml f.flush yield f.path end end def self.options_to_cmd(options, cmd) options.each do |k, v| sep = k.to_s.end_with?("=") ? "" : " " cmd << "#{k}#{sep}#{quote(v)}" end end end