class Md2site::Setup

setupサブコマンドクラス

Constants

ACCESS_WAIT_SEC

WEBサイトへのアクセス待ち時間(秒単位)

Public Class Methods

new(env, mes) click to toggle source

初期化

@param env [Env] 環境クラスのメソッド @param mes [Messagex] Messagexクラスのインスタンス

# File lib/md2site/setup.rb, line 26
def initialize(env, mes)
  @env = env
  @mes = mes
  @category_target = @env.category_target
  absolute_path_status_file = env.conf_hs["ABSOLUTE_PATH_STATUS_FILE"]
  @url = @env.conf_hs["URL"]
  @res = {}

  @mes.add_exitcode("EXIT_CODE_BY_EXCEPTION")
  @mes.add_exitcode("EXIT_CODE_EXECUTE_SETUP_BEFORE_UPDATE_HTMLFILES")
  @mes.add_exitcode("EXIT_CODE_CANNOT_FIND_DEST_DIR")
  @mes.add_exitcode("EXIT_CODE_CANNOT_CONVERT_FROM_HTML_TO_MD")
  @mes.add_exitcode("EXIT_CODE_PANDOC_EXIT_ABNORMALLY")
  @status_file = StatusFile.new(absolute_path_status_file, @env.absolutepath_root, @url, @mes)
end

Public Instance Methods

execute_subcommand(option) click to toggle source

サブコマンド実行

@param option [String] サブコマンドのオプション @return [void]

# File lib/md2site/setup.rb, line 47
def execute_subcommand(option)
  case option.name
  when "contentUpdate"
    update_htmlfiles
  when "zcontents"
    dir = @env.get_filepath(option.value)
    unless dir
      @mes.exc_make_directory(option.value) { FileUtils.mkdir_p(option.value) }
      dir = @env.get_filepath(option.value)
    end
    unless dir || FileTest.directory?(dir)
      @mes.output_fatal("Can't find drectory(=#{dir}")
      exit(@mes.ec("EXIT_CODE_CANNOT_FIND_DIRECTORY"))
    end
    get_remote_contents(dir)
  when "getfiles"
    dir = @env.get_filepath(option.value)
    get_remote_file_headers(dir)
  end
end

Private Instance Methods

current_time() click to toggle source

現在時刻をDatetimeクラスのインスタンスと文字列にする

@return [Array] 第0要素: Datetimeクラスのインスタンス 第1要素: “年月日-時分秒”の形式の文字列

# File lib/md2site/setup.rb, line 177
def current_time
  datetime = DateTime.now
  datetimestr = get_datestring(datetime)
  [datetime, datetimestr]
end
get_date_in_datetime_from_header(headers) click to toggle source

HTTPヘッダのdateフィールドの値を文字列とUNITタイムで取得

@param headers [Hash] HTTPヘッダを表すハッシュ @return [Array] 第0要素: 指定フィールドの値(String) 第1要素: 指定フィールドの値(UNIXタイム)

# File lib/md2site/setup.rb, line 132
def get_date_in_datetime_from_header(headers)
  get_header_value_of_datetime(headers, "date")
end
get_datestring(datetime) click to toggle source

時刻を“年月日-時分秒”の形式の文字列にする

@param datetime [Datetime] Datetimeクラスのインスタンス @return [String] “年月日-時分秒”の形式の文字列

# File lib/md2site/setup.rb, line 169
def get_datestring(datetime)
  datetime.strftime("%Y%m%d-%H%M%S")
end
get_header_value_of_datetime(headers, key) click to toggle source

HTTPヘッダの指定フィールドの値を文字列とUNITタイムで取得する

@param headers [Hash] HTTPヘッダを表すハッシュ @param key [String] HTTPヘッダのフィールドを指定するキー @return [Array] 第0要素: 指定フィールドの値(String) 第1要素: 指定フィールドの値(UNIXタイム)

# File lib/md2site/setup.rb, line 92
def get_header_value_of_datetime(headers, key)
  @res[key] ||= Regexp.compile(Regexp.escape(key))
  keys = headers.keys.select {|x| @res[key].match?(x.downcase) }

  if keys.size == 1
    k = keys.first
    s = headers[k]
    begin
      dt = DateTime.httpdate(s)
      unixtime = dt.to_time.to_i
    rescue ArgumentError => e
      @mes.output_exception(e)
      @mes.output_fatal("s=#{s}")
      exit(@mes.ec("EXIT_CODE_BY_EXCEPTION"))
    rescue Error => e
      @mes.output_exception(e)
      @mes.output_fatal("s=#{s}")
      exit(@mes.ec("EXIT_CODE_BY_EXCEPTION"))
    end
  else
    s = nil
    unixtime = nil
  end
  [s, unixtime]
end
get_modified_in_datetime_from_header(headers) click to toggle source

HTTPヘッダのlast-modifiedフィールドの値を文字列とUNITタイムで取得

@param headers [Hash] HTTPヘッダを表すハッシュ @return [Array] 第0要素: 指定フィールドの値(String) 第1要素: 指定フィールドの値(UNIXタイム)

# File lib/md2site/setup.rb, line 123
def get_modified_in_datetime_from_header(headers)
  get_header_value_of_datetime(headers, "last-modified")
end
get_modified_in_datetime_or_date_in_datetime(url) click to toggle source

指定URLのHTTPヘッダから時刻を表すlast-modifiedフィールドまたはdateフィールのの値を文字列とUNIXタイムで取得

@param url [String] HTTPヘッダを取得したいURL @return [Array] 第0要素: 指定フィールドの値(String) 第1要素: 指定フィールドの値(UNIXタイム)

# File lib/md2site/setup.rb, line 154
def get_modified_in_datetime_or_date_in_datetime(url)
  connection = Faraday.new(url) do |conn|
    conn.use(FaradayMiddleware::FollowRedirects)
    conn.adapter(:net_http)
  end
  @mes.output_debug("url=#{url}")
  res = connection.head(url)
  get_modified_in_datetime_or_date_in_datetime_from_header(res.headers)
end
get_modified_in_datetime_or_date_in_datetime_from_header(headers) click to toggle source

HTTPヘッダから時刻を表すlast-modifiedフィールドまたはdateフィールのの値を文字列とUNIXタイムで取得

@param headers [Hash] HTTPヘッダを表すハッシュ @return [Array] 第0要素: 指定フィールドの値(String) 第1要素: 指定フィールドの値(UNIXタイム)

# File lib/md2site/setup.rb, line 141
def get_modified_in_datetime_or_date_in_datetime_from_header(headers)
  ary = get_modified_in_datetime_from_header(headers)
  unless ary.all?
    ary = get_date_in_datetime_from_header(headers)
  end
  ary
end
get_remote_contents(dir) click to toggle source

指定サイトでダウンロード指定された全URLのをファイルとして、指定ディレクトリ下にダウンロードし、

ダウンロードファイル一覧ファイルを作成し、ダウンロードステータスファイルを更新

@param dir [String] ダウンロードファイルの保存先ディレクトリ @return [void]

# File lib/md2site/setup.rb, line 305
def get_remote_contents(dir)
  _, datetimestr = current_time

  @mes.output_info("dir=#{dir}")
  @mes.output_info("datetimestr=#{datetimestr}")

  last_contents_path = File.absolute_path(File.join(dir, datetimestr))
  @mes.exc_make_directory(last_contents_path) { FileUtils.mkdir_p(last_contents_path) }

  # 保存先ディレクトリ内にダウンロードファイル一覧ファイルを作成
  lf = ListFile.new(last_contents_path, @mes)
  @category_target.each do |_, target_struct|
    # 各ターゲット毎にファイルをダウンロード
    get_remote_contents_subtargets(target_struct[:subTargets], lf, last_contents_path)
  end
  lf.close

  # ダウンロードステータスファイルを更新
  @status_file.last_contents_path = last_contents_path
  @status_file.update
end
get_remote_contents_subtargets(subtarget_hash, listfile, last_contents_path) click to toggle source

指定サイトでダウンロード指定された全URLのをファイルとして、保存先ディレクトリにダウンロードし、

ダウンロードステータスファイルを更新

@param subtarget_hash [Hash] サブターゲット名をキーとしてサブターゲットストラクトを値とするハッシュ @param listfile [Listfile] ダウンロードファイル一覧ファイル @param last_contents_path [String] ダウンロード保存先ディレクトリ @return [void]

# File lib/md2site/setup.rb, line 258
def get_remote_contents_subtargets(subtarget_hash, listfile, last_contents_path)
  subtarget_hash.each do |_, subtarget_struct|
    #        filename = target_def[@env.htmlfile_index]
    unless subtarget_struct.htmldir&.empty?
      filename = File.join(subtarget_struct.htmldir, subtarget_struct.htmlfile)
    else
      filename = subtarget_struct.htmlfile
    end
    next unless subtarget_struct.aliashtmlfile&.empty?

    # file_urlが'//'とならないようにする
    if %r{/$}.match?(@url)
      file_url = URI.join(@url, filename)
    else
      file_url = URI.join(@url, "/", filename)
    end
    # file_urlをダウンロードする
    remote_datetime_str, remote_datetime_unixtime, content = get_remote_file(file_url)
    # ダウンロードできなかった場合はエラーメッセージを表示して、次のサブターゲットのダウンロードに移る
    unless [remote_datetime_str, remote_datetime_unixtime].all?
      @mes.output_error("Can't get content from #{file_url}")
      listfile.add([filename, remote_datetime_str, remote_datetime_unixtime, nil])

      sleep(ACCESS_WAIT_SEC)
      next
    end

    # ダウンロードした内容をファイルに書き込む
    fpath = prepare_new_write_path(last_contents_path, filename)
    @mes.exc_file_write(fpath) do
      File.open(fpath, "w") do |ofile|
        if content
          ofile.puts(content)
        end
      end
    end
    # ダウンロードファイル一覧に追加
    listfile.add([filename, remote_datetime_str, remote_datetime_unixtime, Digest::MD5.hexdigest(content)])
  end
end
get_remote_file(url) click to toggle source

リモートサイトのファイル取得

@param url [String] 取得先URL @return [Array] 第0要素:Datetime 第1要素:UNIXタイム 第2要素:HTTPボディ

# File lib/md2site/setup.rb, line 75
def get_remote_file(url)
  connection = Faraday.new(url) do |conn|
    conn.use(FaradayMiddleware::FollowRedirects)
    conn.adapter(:net_http)
  end
  @mes.output_debug("url=#{url}")
  res = connection.get(url)
  datetime_str, datetime_unix_time = get_modified_in_datetime_or_date_in_datetime_from_header(res.headers)
  [datetime_str, datetime_unix_time, res.body]
end
get_remote_file_headers(dir) click to toggle source

指定サイトでダウンロード指定された全URLのHTTPヘッダの時刻を取得して一覧をファイルに保存

@param dir [String] HTTPヘッダ時刻一覧ファイルの保存先ディレクトリ @return [Array] 第0要素: Datetimeクラスのインスタンス 第1要素: “年月日-時分秒”の形式の文字列 @note 一覧を保存するファイルのファイル名はsite-年月日-時分秒.tsvである

# File lib/md2site/setup.rb, line 189
def get_remote_file_headers(dir)
  _, datetimestr = current_time

  fname = %Q(site-#{datetimestr}.tsv)
  fpath = File.join(dir, fname)

  @mes.exc_file_write(fpath) do
    File.open(fpath, "w") do |ofile|
      @category_target.each do |_k, v|
        v[:subTargets].each do |_k2, subtarget|
          filename = subtarget.htmlfile
          next unless subtarget.aliashtmlfile && !subtarget.aliashtmlfile&.empty?

          if %r{/$}.match?(@url)
            file_url = URI.join(@url, filename)
          else
            file_url = URI.join(@url, "/", filename)
          end
          ary = get_modified_in_datetime_or_date_in_datetime(file_url)
          unless ary.all?
            @mes.output_error("Can't find last-modified header from #{@url}")
          end

          ofile.puts([file_url].join("\t"))
        end
      end
    end
  end
  @status_file.fname = fname
  @status_file.fpath = fpath
  @status_file.last_datetime = datetimestr
  @status_file.update
end
prepare_new_write_path(dir, filename, postfix=nil) click to toggle source

引数で指定したファイルが書込み可能であるように書込み先ディレクトリを作成

@param dir [String] ディレクトリ @param filename [String] ファイルへのパス(ファイル名のみも可)

# File lib/md2site/setup.rb, line 228
def prepare_new_write_path(dir, filename, postfix=nil)
  if postfix
    extname = File.extname(filename)
    basename = File.basename(filename, extname)
    new_fname = %Q(#{basename}#{postfix}#{extname})
  else
    basename = File.basename(filename)
    new_fname = basename
  end

  dirname = File.dirname(filename)
  if dirname != "."
    dirpath = File.join(dir, dirname)
    @mes.exc_make_directory(dirpath) { FileUtils.mkdir_p(dirpath) }
    fpath = File.join(dirpath, new_fname)
  else
    fpath = File.join(dir, new_fname)
  end

  fpath
end
simple_html2md(input_htmlfname, outputmd) click to toggle source

HTMLファイルをMarkdown形式に変換する

@param input_htmlfname [String] 変換元HTMLファイル名 @param outputmd [String] 変換したMakrdown形式ファイル名 @return [void] @note HTMLファイルからMarkdown形式ファイルへの変換にはpandocを利用するため、pandoc

がインストールされていることが前提
# File lib/md2site/setup.rb, line 415
def simple_html2md(input_htmlfname, outputmd)
  ret = false
  _, _, s = Open3.capture3(%Q(pandoc -o #{outputmd} -t markdown #{input_htmlfname}))

  if s.exited?
    if s.exitstatus == 0
      ret = true
    else
      @mes.output_error("Can't convert from html to md by pandoc(IN:#{input_htmlfname} OUT:#{outputmd}(exit_code=#{s.exitstatus})")
      exit(@mes.ec("EXIT_CODE_CANNOT_CONVERT_FROM_HTML_TO_MD"))
    end
  else
    @mes.output_error("Pandoc exit abnormally")
    exit(@mes.ec("EXIT_CODE_PANDOC_EXIT_ABNORMALLY"))
  end

  ret
end
update_htmlfiles() click to toggle source

ダウンロードステータスファイルを更新ダウンロード保存先ディレクトリから指定サブターゲットのHTMLファイルをサブターゲットで

指定されてディレクトリにコピーし、3分割し、中間部分をMarkdown形式に変換する

@return [void]

# File lib/md2site/setup.rb, line 375
def update_htmlfiles
  # 有効なダウンロードステータスファイルが存在しなければexitする
  if @status_file.nil? || @status_file.last_contents_path.nil? || @status_file.last_contents_path.empty?
    @mes.output_info("@status_file=#{@status_file}")
    unless @status_file.nil?
      @mes.output_info("@status_file.last_contents_path=#{@status_file.last_contents_path}")
    end
    exit(@mes.ec("EXIT_CODE_EXECUTE_SETUP_BEFORE_UPDATE_HTMLFILES"))
  else
    # 全ターゲットの全サブターゲットのうち、エイリアスHTMLファイルが指定されておらず、かつ未ダウンロード
    #   のもののみをダウンロードする
    @category_target.each do |_name, category_struct|
      category_struct.subTargets.each do |_k, v|
        # エイリアスHTMLファイルが指定されていても、ワークディレクトリは必要なため、ここで作成する
        path = File.join(@env.absolutepath_root, v.workDir)
        @mes.exc_make_directory(path) { FileUtils.mkdir_p(path) }

        next unless v.aliashtmlfile.empty?
        filename = v.htmlfile
        next if filename.empty?

        src_fpath = File.join(@status_file.last_contents_path, filename)
        unless File.exist?(src_fpath)
          @mes.output_info("#{src_fpath} doesn't exist")
          next
        end
        update_htmlfiles_subtarget(v, src_fpath)
      end
    end
  end
end
update_htmlfiles_subtarget(subtarget, src_fpath) click to toggle source

ダウンロード保存先ディレクトリから指定サブターゲットのHTMLファイルをサブターゲットで

指定されてディレクトリにコピーし、3分割し、中間部分をMarkdown形式に変換する

@param subtarget [String] サブターゲットストラクト @param src_fpath [String] コピー元ファイルパス @return [void] @note HTMLファイルからMarkdown形式ファイルへの変換にはpandocを利用するため、pandoc

がインストールされていることが前提
# File lib/md2site/setup.rb, line 336
def update_htmlfiles_subtarget(subtarget, src_fpath)
  dest_fpath = prepare_new_write_path(@env.absolutepath_root, subtarget.filedir.html_input)
  unless dest_fpath
    dir = File.dirname(subtarget.filedir.html_input)
    path = File.join(@env.absolutepath_root, dir)
    @mes.exc_make_directory(path) { FileUtils.mkdir_p(path) }
    dest_fpath2 = prepare_new_write_path(@env.absolutepath_root, subtarget.filedir.html_input)
    if dest_fpath2
      dest_fpath = dest_fpath2
    else
      @mes.output_fatal("Can't find dest dir(#{path})")
      exit(@mes.ec("EXIT_CODE_CANNOT_FIND_DEST_DIR"))
    end
  end

  @mes.exc_file_copy(src_fpath, dest_fpath) { FileUtils.cp(src_fpath, dest_fpath) }
  @mes.output_info("HtmlUtils.divideHtml dest_fpath=#{dest_fpath}")
  ary = HTMLUtils.new(dest_fpath, @mes).divide_html
  dir = File.dirname(dest_fpath)
  (0..2).each do |x|
    ofname = File.join(dir, %Q(#{x}.html))
    @mes.exc_file_write(ofname) { File.open(ofname, "w") {|f| f.puts(ary[x]) } }
  end
  in_html = File.join(dir, %Q(1.html))
  unless File.exist?(in_html)
    @mes.output_fatal("Can't find file(=#{in_html}")
    exit(@mes.ec("EXIT_CODE_CANNOT_FIND_FILE"))
  end
  out_orig_md = prepare_new_write_path(@env.absolutepath_root, subtarget.filedir.input_md, "_orig")
  simple_html2md(in_html, out_orig_md)
  out_md = File.join(@env.absolutepath_root, subtarget.filedir.input_md)
  @mes.exc_file_copy(out_orig_md, out_md) { FileUtils.cp(out_orig_md, out_md) } unless File.exist?(out_md)
end