lib/asciidoctor-epub3/packager.rb in asciidoctor-epub3-1.5.0.alpha.10 vs lib/asciidoctor-epub3/packager.rb in asciidoctor-epub3-1.5.0.alpha.11

- old
+ new

@@ -1,15 +1,14 @@ # frozen_string_literal: true -require_relative 'core_ext/string' autoload :FileUtils, 'fileutils' autoload :Open3, 'open3' -autoload :Shellwords, 'shellwords' module Asciidoctor module Epub3 module GepubBuilderMixin + include ::Asciidoctor::Logging DATA_DIR = ::File.expand_path ::File.join(::File.dirname(__FILE__), '..', '..', 'data') SAMPLES_DIR = ::File.join DATA_DIR, 'samples' LF = ?\n CharEntityRx = ContentConverter::CharEntityRx XmlElementRx = ContentConverter::XmlElementRx @@ -124,21 +123,21 @@ imagesdir = (imagesdir == '.' ? nil : %(#{imagesdir}/)) if (image_path = doc.attr 'front-cover-image') image_attrs = {} if (image_path.include? ':') && image_path =~ ImageMacroRx - warn %(asciidoctor: WARNING: deprecated block macro syntax detected in front-cover-image attribute) if image_path.start_with? 'image::' + logger.warn %(deprecated block macro syntax detected in front-cover-image attribute) if image_path.start_with? 'image::' image_path = %(#{imagesdir}#{$1}) (::Asciidoctor::AttributeList.new $2).parse_into image_attrs, %w(alt width height) unless $2.empty? end workdir = (workdir = doc.attr 'docdir').nil_or_empty? ? '.' : workdir if ::File.readable? ::File.join(workdir, image_path) unless !image_attrs.empty? && (width = image_attrs['width']) && (height = image_attrs['height']) width, height = 1050, 1600 end else - warn %(asciidoctor: ERROR: #{::File.basename doc.attr('docfile')}: front cover image not found or readable: #{::File.expand_path image_path, workdir}) + logger.error %(#{::File.basename doc.attr('docfile')}: front cover image not found or readable: #{::File.expand_path image_path, workdir}) image_path = nil end end image_path, workdir, width, height = DefaultCoverImage, DATA_DIR, 1050, 1600 unless image_path @@ -221,19 +220,20 @@ def add_content_images doc, images docimagesdir = (doc.attr 'imagesdir', '.').chomp '/' docimagesdir = (docimagesdir == '.' ? nil : %(#{docimagesdir}/)) + self_logger = logger workdir = (workdir = doc.attr 'docdir').nil_or_empty? ? '.' : workdir resources workdir: workdir do images.each do |image| if (image_path = image[:path]).start_with? %(#{docimagesdir}jacket/cover.) - warn %(asciidoctor: WARNING: image path is reserved for cover artwork: #{image_path}; skipping image found in content) + self_logger.warn %(image path is reserved for cover artwork: #{image_path}; skipping image found in content) elsif ::File.readable? image_path file image_path else - warn %(asciidoctor: ERROR: #{::File.basename image[:docfile]}: image not found or not readable: #{::File.expand_path image_path, workdir}) + self_logger.error %(#{::File.basename image[:docfile]}: image not found or not readable: #{::File.expand_path image_path, workdir}) end end end nil end @@ -245,26 +245,27 @@ resources do file %(#{imagesdir}avatars/default.jpg) => ::File.join(DATA_DIR, 'images/default-avatar.jpg') file %(#{imagesdir}headshots/default.jpg) => ::File.join(DATA_DIR, 'images/default-headshot.jpg') end + self_logger = logger workdir = (workdir = doc.attr 'docdir').nil_or_empty? ? '.' : workdir resources do usernames.each do |username| avatar = %(#{imagesdir}avatars/#{username}.jpg) if ::File.readable? (resolved_avatar = (::File.join workdir, avatar)) file avatar => resolved_avatar else - warn %(asciidoctor: ERROR: avatar for #{username} not found or readable: #{avatar}; falling back to default avatar) + self_logger.error %(avatar for #{username} not found or readable: #{avatar}; falling back to default avatar) file avatar => ::File.join(DATA_DIR, 'images/default-avatar.jpg') end headshot = %(#{imagesdir}headshots/#{username}.jpg) if ::File.readable? (resolved_headshot = (::File.join workdir, headshot)) file headshot => resolved_headshot elsif doc.attr? 'builder', 'editions' - warn %(asciidoctor: ERROR: headshot for #{username} not found or readable: #{headshot}; falling back to default headshot) + self_logger.error %(headshot for #{username} not found or readable: #{headshot}; falling back to default headshot) file headshot => ::File.join(DATA_DIR, 'images/default-headshot.jpg') end end end nil @@ -473,12 +474,12 @@ (@last_defined_item['properties'] || []).include? property end end class Packager - KINDLEGEN = ENV['KINDLEGEN'] || 'kindlegen' - EPUBCHECK = ENV['EPUBCHECK'] || %(epubcheck#{::Gem.win_platform? ? '.bat' : '.sh'}) + include ::Asciidoctor::Logging + EpubExtensionRx = /\.epub$/i KindlegenCompression = ::Hash['0', '-c0', '1', '-c1', '2', '-c2', 'none', '-c0', 'standard', '-c1', 'huffdic', '-c2'] def initialize spine_doc, spine, format = :epub3, _options = {} @document = spine_doc @@ -550,14 +551,18 @@ # TODO: getting author list should be a method on Asciidoctor API contributors(*authors) if doc.attr? 'revdate' - # TODO: ensure this is a real date - date doc.attr('revdate') + begin + date doc.attr('revdate') + rescue ArgumentError => e + logger.error %(#{::File.basename doc.attr('docfile')}: failed to parse revdate: #{e}, using current time as a fallback) + date ::Time.now + end else - date ::Time.now.strftime('%Y-%m-%dT%H:%M:%SZ') + date ::Time.now end description doc.attr('description') if doc.attr? 'description' (collect_keywords doc, spine).each do |s| @@ -581,11 +586,11 @@ ::FileUtils.mkdir_p dest unless ::File.directory? dest epub_file = fmt == :kf8 ? %(#{::Asciidoctor::Helpers.rootname target}-kf8.epub) : target builder.generate_epub epub_file - puts %(Wrote #{fmt.upcase} to #{epub_file}) if $VERBOSE + logger.debug %(Wrote #{fmt.upcase} to #{epub_file}) if options[:extract] extract_dir = epub_file.sub EpubExtensionRx, '' ::FileUtils.remove_dir extract_dir if ::File.directory? extract_dir ::Dir.mkdir extract_dir ::Dir.chdir extract_dir do @@ -597,11 +602,11 @@ end entry.extract end end end - puts %(Extracted #{fmt.upcase} to #{extract_dir}) if $VERBOSE + logger.debug %(Extracted #{fmt.upcase} to #{extract_dir}) end if fmt == :kf8 # QUESTION shouldn't we validate this epub file too? distill_epub_to_mobi epub_file, target, options[:compress] @@ -609,39 +614,70 @@ validate_epub epub_file end end def distill_epub_to_mobi epub_file, target, compress - kindlegen_cmd = KINDLEGEN - unless ::File.executable? kindlegen_cmd + if !(kindlegen_cmd = ENV['kindlegen']).nil? + argv = [kindlegen_cmd] + else require 'kindlegen' unless defined? ::Kindlegen - kindlegen_cmd = ::Kindlegen.command + argv = [::Kindlegen.command.to_s] end mobi_file = ::File.basename target.sub(EpubExtensionRx, '.mobi') compress_flag = KindlegenCompression[compress ? (compress.empty? ? '1' : compress.to_s) : '0'] - cmd = [kindlegen_cmd, '-dont_append_source', compress_flag, '-o', mobi_file, epub_file].compact - ::Open3.popen2e ::Shellwords.join(cmd) do |_input, output, _wait_thr| - output.each {|line| puts line } unless $VERBOSE.nil? + argv += ['-dont_append_source', compress_flag, '-o', mobi_file, epub_file].compact + + # This duplicates Kindlegen.run, but we want to override executable + out, err, res = Open3.capture3(*argv) do |r| + r.force_encoding 'UTF-8' if windows? && r.respond_to?(:force_encoding) end - puts %(Wrote MOBI to #{::File.join ::File.dirname(epub_file), mobi_file}) if $VERBOSE + + out.each_line do |line| + logger.info line + end + err.each_line do |line| + log_line line + end + + output_file = ::File.join ::File.dirname(epub_file), mobi_file + if res.success? + logger.debug %(Wrote MOBI to #{output_file}) + else + logger.error %(kindlegen failed to write MOBI to #{output_file}) + end end def validate_epub epub_file - if ::File.executable? EPUBCHECK - argv = [EPUBCHECK] + if !(epubcheck = ENV['EPUBCHECK']).nil? + argv = [epubcheck] else argv = [::Gem.ruby, ::Gem.bin_path('epubcheck-ruby', 'epubcheck')] end - if $VERBOSE.nil? - argv << '-q' - else - argv << '-w' + argv += ['-w', epub_file] + out, err, res = Open3.capture3(*argv) + + out.each_line do |line| + logger.info line end - argv << epub_file + err.each_line do |line| + log_line line + end - ::Open3.popen2e ::Shellwords.join(argv) do |_input, output, _wait_thr| - output.each {|line| puts line } + logger.error %(EPUB validation failed: #{epub_file}) unless res.success? + end + + def log_line line + line = line.strip + + if line =~ /^fatal/i + logger.fatal line + elsif line =~ /^error/i + logger.error line + elsif line =~ /^warning/i + logger.warn line + else + logger.info line end end end end end