module Md2site # # makeサブコマンドクラス # class Make # # 初期化 # @param env [Env] Envクラスのインスタンス # @param mes [Messagex] Messagexクラスのインスタンス # @param verbose [Boolean] FileUtilsクラスのメソッドのverbose引数に与える値 # @param str_variable [String] 2段階の変数置換が必要なeRubyスクリプト(一度置換をし、さらにもう一度置換が必要なeRubyスクリプト) # @param str_static [String] 1段階の変数置換のみが必要なeRubyスクリプト(一度置換をしたら、その後は置換が必要ないeRubyスクリプト) # @param obj_by_yaml [Hash] 変数置換に用いるハッシュ def initialize(env, mes, verbose, str_variable, str_static, obj_by_yaml) @env = env @mes = mes @verbose = verbose @str_variable = str_variable @str_static = str_static @obj_by_yaml = obj_by_yaml @template_dir = @env.conf_hs["TEMPLELATE_DIR"] @default_table_template = @env.conf_hs["DEFAULT_TABLE_TEMPLATE"] # 5col_no_attr_b.erb end # # 引数optionでの指定に従いサブコマンドを実行 # @param target_command [String] ターゲットコマンド名 # @param subtarget_command [String] サブターゲットコマンド名 def execute_subcommand(target_command, subtarget_command) if subtarget_command == SUB_TARGET_COMMAND_OF_ALL do_multiple_commands(target_command) else do_single_command(target_command, subtarget_command) end end # # 指定ターゲットコマンドに属する全サブターゲットコマンドを順次実行する # @param target_command [String] ターゲットコマンド名 def do_multiple_commands(target_command) ary = @env.get_subtarget_commands(target_command) if !ary.empty? ary.map do |subtarget_command, _v| @mes.output_info("#{target_command} #{subtarget_command}") do_single_command(target_command, subtarget_command) end else @mes.output_fatal("Illeagel targetcommand(#{target_command}") exit(@mes.ec("EXIT_CODE_ILLEAGAL_TARGETCOMMAND")) end end private # # ターゲットコマンド名、サブターゲットコマンド名の組み合わせを実行する # @param target_command [String] ターゲットコマンド名 # @param subtarget_command [String] サブターゲットコマンド名 def do_single_command(target_command, subtarget_command) target, subtarget = @env.get_target_and_subtarget(target_command, subtarget_command) @mes.output_info(%Q(target=#{target})) @mes.output_info(%Q(subtarget=#{subtarget})) unless target @mes.output_fatal(%Q(Cannot find target by #{target_command})) exit(@mes.ec("EXIT_CODE_BY_CANNOT_FIND_TARGET")) end unless subtarget @mes.output_fatal(%Q(Cannot find subtarget by #{subtarget_command})) exit(@mes.ec("EXIT_CODE_BY_CANNOT_FIND_SUBTARGET")) end execute_single_command(target, subtarget) end # # 指定パスが有効なファイルであるか調べる # @param fname [String] ファイルのパス # @return [Boolean] true:有効なファイルパスである false:有効なファイルパスでない def check_valid_src_file(fname) valid_src_file = true ret = FileTest.size?(fname) if !ret || (ret == 0) valid_src_file = false elsif FileTest.directory?(fname) valid_src_file = false elsif File.read(fname).strip.empty? valid_src_file = false end valid_src_file end # # eRubyスクリプトを用いてMarkdown形式ファイルを生成 # @param target_struct [Struct] ターゲットストラクト # @param template_struct [Struct] テンプレートストラクト def execute_single_command_for_template(target_struct, template_struct) # 既存のファイルを読み込む if template_struct.kind == :INCLUDE dataop = :FILE_INCLUDE # 読み込み元のファイルが存在しなければ、あらかじめ作成する unless check_valid_src_file(template_struct.datafname) src_subtarget = @env.get_sub_target(target_struct.name, template_struct.src_subtarget_name) execute_single_command(target_struct, src_subtarget) end command_make_md(@env.absolutepath_root, template_struct.datafname, template_struct.outputfname, dataop, nil, { template_struct.macroname => template_struct.datafname }) # YAML形式ファイルを、eRubyスクリプトを用いて、Markdown形式ファイルに変換する else dataop = :YAML_TO_MD command_make_md(@env.absolutepath_root, template_struct.datafname, template_struct.outputfname, dataop, template_struct.templatefname, { template_struct.macroname => template_struct.outputfname }) end end # # Markdown形式ファイルをeRubyスクリプトを用いて # @param target_struct [Struct] ターゲットストラクト # @param subtarget_struct [Struct] サブターゲットストラクト def execute_single_command(target_struct, subtarget_struct) # 設定されていれば、全テンプレートストラクトに対して、テンプレートを用いてMarkdown形式ファイルを生成 unless subtarget_struct.templates.empty? subtarget_struct.templates.each do |template_struct| execute_single_command_for_template(target_struct, template_struct) end end # eRubyスクリプト内でファイルを表すマクロ名と実際のファイルパスの対応をハッシュで実現 ary = subtarget_struct.templates.map {|x| [x.macroname, x.outputfname] }.flatten hash = Hash[*ary] # Markdown形式ファイルから生成するHTMLファイルは、HTMLのbodyタグ内の部分である # HTMLの先頭からの直前までと、から最後までを別途取得して、最終的にそれらを結合してHTMLファイルにする。 parta_html = get_part_html(target_struct, subtarget_struct, :partA) partc_html = get_part_html(target_struct, subtarget_struct, :partC) datafile = subtarget_struct.filedir.input_md outputfile = subtarget_struct.filedir.output_md dataop = :FILE_INCLUDE templatefile = nil # HTMLファイルに変換する元となるMarkdown形式ファイル生成 command_make_md(@env.absolutepath_root, datafile, outputfile, dataop, templatefile, hash) outputfile_md = subtarget_struct.filedir.output_md root_output_md = subtarget_struct.filedir.root_output_md out_htmlfname = subtarget_struct.filedir.html_output # Markdown形式ファイルをHTMLに変換、結合して最終的なHTMLファイルを生成 command_make_html(@env.absolutepath_root, outputfile_md, root_output_md, parta_html, partc_html, out_htmlfname) end # # サブターゲットでエイリアスが指定されていれば、エイリアスを生成するサブターゲットを得る # @param target_struct [Struct] ターゲットストラクト # @param subtarget_struct [Struct] サブターゲットストラクト # @return [Struct] 有効なサブターゲットストラクト def get_effective_subtarget(target_struct, subtarget_struct) if subtarget_struct.aliashtmldir == "" if subtarget_struct.aliashtmlfile == "" htmlfpath = nil else htmlfpath = subtarget_struct.aliashtmlfile end else htmlfpath = File.join(subtarget_struct.aliashtmldir, subtarget_struct.aliashtmlfile) end if htmlfpath subtarget_struct_x = @env.get_subtarget_by_htmlfile(target_struct.name, htmlfpath) else subtarget_struct_x = subtarget_struct end subtarget_struct_x end # # 指定されたパートに対応するHTMLファイルパスを得る # @param target_struct [Struct] ターゲットストラクト # @param subtarget_struct [Struct] サブターゲットストラクト # @param kind [Symbol] :partA パートA :partB パートB def get_part_html(target_struct, subtarget_struct, kind) subtarget_x = get_effective_subtarget(target_struct, subtarget_struct) path = "" case kind when :partA path = subtarget_x.filedir.partAhtml when :partC path = subtarget_x.filedir.partChtml end path end def command_make_md(src_dir, datafile, outputfile, dataop, templatefile, auxhs={}) @mes.output_info(%Q!command_make_md(#{datafile}, #{outputfile}, #{dataop}, #{templatefile}, #{auxhs}!) if src_dir datafile = File.join(src_dir, datafile) if datafile outputfile = File.join(src_dir, outputfile) if outputfile end optsx = {} optsx["data"] = datafile optsx["output"] = outputfile optsx["dataop"] = dataop mmt = Mdextab::Makemdtab.new(optsx, @str_variable, @str_static, @obj_by_yaml, @mes) if templatefile if src_dir template_fullpath = File.join(src_dir, @template_dir, templatefile) else template_fullpath = File.join(@template_dir, templatefile) end else template_fullpath = @default_table_template end mmt.make_md2(src_dir, template_fullpath, auxhs) mmt.post_process end def simple_md2html(inputmd, output_htmlfname) @mes.output_info(%Q(pandoc -o #{output_htmlfname} -t html5 #{inputmd})) ret = false _, _, s = Open3.capture3(%Q(pandoc -o #{output_htmlfname} -t html5 #{inputmd})) if s.exited? if s.exitstatus == 0 ret = true else @mes.output_error("Can't convert from md to html by pandoc(exit_code=#{s.exitstatus})") exit(@mes.ec("EXIT_CODE_CANNOT_CONVERT_FROM_MD_TO_HTML")) end else @mes.output_error("Pandoc exit abnormally") exit(@mes.ec("EXIT_CODE_PANDOC_EXIT_ABNORMALLY")) end ret end def output_html(out_htmlfname, mode, parta, content, partb) File.open(out_htmlfname, mode) do |f| f.write(parta) f.write(content) f.write(partb) end end def md2html(root_outputmd, out_htmlfname, parta, partb) tmpdir = File.dirname(out_htmlfname) tmpbasename = File.basename(out_htmlfname) content_htmlfname = File.join(tmpdir, tmpbasename + ".tmp") unless root_outputmd @mes.output_fatal("Can't find file(=#{root_outputmd}") exit(@mes.ec("EXIT_CODE_CANNOT_FIND_FILE")) end @mes.output_debug("root_outputmd=#{root_outputmd}") @mes.output_debug("content_htmlfname=#{content_htmlfname}") ret = simple_md2html(root_outputmd, content_htmlfname) return unless ret ret = simple_md2html(root_outputmd, "x.html") unless ret tmpf.close(true) return end content = "" @mes.exc_file_read(content_htmlfname) { content = File.readlines(content_htmlfname).join } @mes.output_debug("file_read #{content_htmlfname}") # @mes.output_debug("content #{content}") @mes.exc_file_write(out_htmlfname) { output_html(out_htmlfname, "w", parta, content, partb) } @mes.output_debug("file_write #{out_htmlfname}") # File.unlink(content_htmlfname) end def command_make_html(src_dir, outputfile_md, root_output_md, parta_html, partc_html, out_htmlfname) @mes.output_info(%Q!command_makehtml(#{outputfile_md}, #{root_output_md}, #{parta_html} #{partc_html} #{out_htmlfname}!) if src_dir outputfile_md = File.join(src_dir, outputfile_md) if outputfile_md root_output_md = File.join(src_dir, root_output_md) if root_output_md parta_html = File.join(src_dir, parta_html) if parta_html partc_html = File.join(src_dir, partc_html) if partc_html out_htmlfname = File.join(src_dir, out_htmlfname) if out_htmlfname end optsx = {} m = Mdextab::Mdextab.new(optsx, outputfile_md, root_output_md, @mes) m.parse(@obj_by_yaml) m.post_process parta = Filex::Filex.check_and_load_file(parta_html, @mes) partc = Filex::Filex.check_and_load_file(partc_html, @mes) md2html(root_output_md, out_htmlfname, parta, partc) end end end