md2site 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +30 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +138 -0
  6. data/.rubocop_todo.yml +47 -0
  7. data/.travis.yml +7 -0
  8. data/Gemfile +8 -0
  9. data/Gemfile.lock +98 -0
  10. data/LICENSE +8 -0
  11. data/LICENSE.txt +8 -0
  12. data/README.md +39 -0
  13. data/Rakefile +6 -0
  14. data/bin/console +14 -0
  15. data/bin/md2site +157 -0
  16. data/bin/setup +8 -0
  17. data/data/conf/conf-sample.yml +5 -0
  18. data/data/conf/conf.sh +32 -0
  19. data/data/conf/setting.yml +3 -0
  20. data/data/conf/site.tsv +1 -0
  21. data/data/template/5col_no_attr.erb +72 -0
  22. data/data/template/5col_no_attr_b.erb +72 -0
  23. data/data/template/functions_static.erb +10 -0
  24. data/data/template/functions_variable.erb +3 -0
  25. data/data/template2/contest_notification.erb +16 -0
  26. data/data/template2/contest_notification_2.erb +34 -0
  27. data/data/template2/contest_winners.erb +69 -0
  28. data/data/template2/contest_winners_statement.erb +1 -0
  29. data/data/testdata/conf-blog.yml +6 -0
  30. data/data/testdata/conf-download.yml +6 -0
  31. data/data/testdata/conf-link.yml +6 -0
  32. data/data/testdata/conf-profile.yml +6 -0
  33. data/data/testdata/conf-top.yml +6 -0
  34. data/data/testdata/site.tsv +5 -0
  35. data/data/testdata0/conf-appliction.yml +1 -0
  36. data/data/testdata0/conf-attempt.yml +69 -0
  37. data/data/testdata0/conf-autosar.yml +11 -0
  38. data/data/testdata0/conf-community.yml +3 -0
  39. data/data/testdata0/conf-document.yml +1 -0
  40. data/data/testdata0/conf-download.yml +1 -0
  41. data/data/testdata0/conf-edu.yml +52 -0
  42. data/data/testdata0/conf-etc.yml +1 -0
  43. data/data/testdata0/conf-members.yml +2 -0
  44. data/data/testdata0/conf-product.yml +37 -0
  45. data/data/testdata0/conf-project.yml +14 -0
  46. data/data/testdata0/conf-rtk.yml +25 -0
  47. data/data/testdata0/conf-top.yml +1 -0
  48. data/data/testdata0/setting.yml +33 -0
  49. data/data/testdata0/site.tsv +123 -0
  50. data/lib/md2site/env.rb +649 -0
  51. data/lib/md2site/htmlutils.rb +142 -0
  52. data/lib/md2site/htmlutils0.rb +223 -0
  53. data/lib/md2site/info.rb +17 -0
  54. data/lib/md2site/init.rb +90 -0
  55. data/lib/md2site/listfile.rb +22 -0
  56. data/lib/md2site/make.rb +295 -0
  57. data/lib/md2site/nkfguess.rb +33 -0
  58. data/lib/md2site/setup.rb +358 -0
  59. data/lib/md2site/statusfile.rb +75 -0
  60. data/lib/md2site/testdata.rb +50 -0
  61. data/lib/md2site/testx.rb +73 -0
  62. data/lib/md2site/version.rb +3 -0
  63. data/lib/md2site.rb +161 -0
  64. data/md2site.gemspec +59 -0
  65. metadata +359 -0
@@ -0,0 +1,295 @@
1
+ module Md2site
2
+ #
3
+ # makeサブコマンドクラス
4
+ #
5
+ class Make
6
+ #
7
+ # 初期化
8
+ # @param env [Env] Envクラスのインスタンス
9
+ # @param mes [Messagex] Messagexクラスのインスタンス
10
+ # @param verbose [Boolean] FileUtilsクラスのメソッドのverbose引数に与える値
11
+ # @param str_variable [String] 2段階の変数置換が必要なeRubyスクリプト(一度置換をし、さらにもう一度置換が必要なeRubyスクリプト)
12
+ # @param str_static [String] 1段階の変数置換のみが必要なeRubyスクリプト(一度置換をしたら、その後は置換が必要ないeRubyスクリプト)
13
+ # @param obj_by_yaml [Hash] 変数置換に用いるハッシュ
14
+ def initialize(env, mes, verbose, str_variable, str_static, obj_by_yaml)
15
+ @env = env
16
+ @mes = mes
17
+ @verbose = verbose
18
+ @str_variable = str_variable
19
+ @str_static = str_static
20
+ @obj_by_yaml = obj_by_yaml
21
+ @template_dir = @env.conf_hs["TEMPLELATE_DIR"]
22
+ @default_table_template = @env.conf_hs["DEFAULT_TABLE_TEMPLATE"] # 5col_no_attr_b.erb
23
+ end
24
+
25
+ #
26
+ # 引数optionでの指定に従いサブコマンドを実行
27
+ # @param target_command [String] ターゲットコマンド名
28
+ # @param subtarget_command [String] サブターゲットコマンド名
29
+ def execute_subcommand(target_command, subtarget_command)
30
+ if subtarget_command == SUB_TARGET_COMMAND_OF_ALL
31
+ do_multiple_commands(target_command)
32
+ else
33
+ do_single_command(target_command, subtarget_command)
34
+ end
35
+ end
36
+
37
+ #
38
+ # 指定ターゲットコマンドに属する全サブターゲットコマンドを順次実行する
39
+ # @param target_command [String] ターゲットコマンド名
40
+ def do_multiple_commands(target_command)
41
+ ary = @env.get_subtarget_commands(target_command)
42
+ if !ary.empty?
43
+ ary.map do |subtarget_command, _v|
44
+ @mes.output_info("#{target_command} #{subtarget_command}")
45
+ do_single_command(target_command, subtarget_command)
46
+ end
47
+ else
48
+ @mes.output_fatal("Illeagel targetcommand(#{target_command}")
49
+ exit(@mes.ec("EXIT_CODE_ILLEAGAL_TARGETCOMMAND"))
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ #
56
+ # ターゲットコマンド名、サブターゲットコマンド名の組み合わせを実行する
57
+ # @param target_command [String] ターゲットコマンド名
58
+ # @param subtarget_command [String] サブターゲットコマンド名
59
+ def do_single_command(target_command, subtarget_command)
60
+ target, subtarget = @env.get_target_and_subtarget(target_command, subtarget_command)
61
+ @mes.output_info(%Q(target=#{target}))
62
+ @mes.output_info(%Q(subtarget=#{subtarget}))
63
+ unless target
64
+ @mes.output_fatal(%Q(Cannot find target by #{target_command}))
65
+ exit(@mes.ec("EXIT_CODE_BY_CANNOT_FIND_TARGET"))
66
+ end
67
+
68
+ unless subtarget
69
+ @mes.output_fatal(%Q(Cannot find subtarget by #{subtarget_command}))
70
+ exit(@mes.ec("EXIT_CODE_BY_CANNOT_FIND_SUBTARGET"))
71
+ end
72
+
73
+ execute_single_command(target, subtarget)
74
+ end
75
+
76
+ #
77
+ # 指定パスが有効なファイルであるか調べる
78
+ # @param fname [String] ファイルのパス
79
+ # @return [Boolean] true:有効なファイルパスである false:有効なファイルパスでない
80
+ def check_valid_src_file(fname)
81
+ valid_src_file = true
82
+
83
+ ret = FileTest.size?(fname)
84
+ if !ret || (ret == 0)
85
+ valid_src_file = false
86
+ elsif FileTest.directory?(fname)
87
+ valid_src_file = false
88
+ elsif File.read(fname).strip.empty?
89
+ valid_src_file = false
90
+ end
91
+ valid_src_file
92
+ end
93
+
94
+ #
95
+ # eRubyスクリプトを用いてMarkdown形式ファイルを生成
96
+ # @param target_struct [Struct] ターゲットストラクト
97
+ # @param template_struct [Struct] テンプレートストラクト
98
+ def execute_single_command_for_template(target_struct, template_struct)
99
+ # 既存のファイルを読み込む
100
+ if template_struct.kind == :INCLUDE
101
+ dataop = :FILE_INCLUDE
102
+ # 読み込み元のファイルが存在しなければ、あらかじめ作成する
103
+ unless check_valid_src_file(template_struct.datafname)
104
+ src_subtarget = @env.get_sub_target(target_struct.name, template_struct.src_subtarget_name)
105
+ execute_single_command(target_struct, src_subtarget)
106
+ end
107
+ command_make_md(@env.absolutepath_root, template_struct.datafname, template_struct.outputfname, dataop, nil, { template_struct.macroname => template_struct.datafname })
108
+ # YAML形式ファイルを、eRubyスクリプトを用いて、Markdown形式ファイルに変換する
109
+ else
110
+ dataop = :YAML_TO_MD
111
+ command_make_md(@env.absolutepath_root, template_struct.datafname, template_struct.outputfname, dataop, template_struct.templatefname, { template_struct.macroname => template_struct.outputfname })
112
+ end
113
+ end
114
+
115
+ #
116
+ # Markdown形式ファイルをeRubyスクリプトを用いて
117
+ # @param target_struct [Struct] ターゲットストラクト
118
+ # @param subtarget_struct [Struct] サブターゲットストラクト
119
+ def execute_single_command(target_struct, subtarget_struct)
120
+ # 設定されていれば、全テンプレートストラクトに対して、テンプレートを用いてMarkdown形式ファイルを生成
121
+ unless subtarget_struct.templates.empty?
122
+ subtarget_struct.templates.each do |template_struct|
123
+ execute_single_command_for_template(target_struct, template_struct)
124
+ end
125
+ end
126
+ # eRubyスクリプト内でファイルを表すマクロ名と実際のファイルパスの対応をハッシュで実現
127
+ ary = subtarget_struct.templates.map {|x| [x.macroname, x.outputfname] }.flatten
128
+ hash = Hash[*ary]
129
+ # Markdown形式ファイルから生成するHTMLファイルは、HTMLのbodyタグ内の部分である
130
+ # HTMLの先頭から<body>の直前までと、</body>から最後までを別途取得して、最終的にそれらを結合してHTMLファイルにする。
131
+ parta_html = get_part_html(target_struct, subtarget_struct, :partA)
132
+ partc_html = get_part_html(target_struct, subtarget_struct, :partC)
133
+
134
+ datafile = subtarget_struct.filedir.input_md
135
+ outputfile = subtarget_struct.filedir.output_md
136
+ dataop = :FILE_INCLUDE
137
+ templatefile = nil
138
+ # HTMLファイルに変換する元となるMarkdown形式ファイル生成
139
+ command_make_md(@env.absolutepath_root, datafile, outputfile, dataop, templatefile, hash)
140
+
141
+ outputfile_md = subtarget_struct.filedir.output_md
142
+ root_output_md = subtarget_struct.filedir.root_output_md
143
+ out_htmlfname = subtarget_struct.filedir.html_output
144
+ # Markdown形式ファイルをHTMLに変換、結合して最終的なHTMLファイルを生成
145
+ command_make_html(@env.absolutepath_root, outputfile_md, root_output_md, parta_html, partc_html, out_htmlfname)
146
+ end
147
+
148
+ #
149
+ # サブターゲットでエイリアスが指定されていれば、エイリアスを生成するサブターゲットを得る
150
+ # @param target_struct [Struct] ターゲットストラクト
151
+ # @param subtarget_struct [Struct] サブターゲットストラクト
152
+ # @return [Struct] 有効なサブターゲットストラクト
153
+ def get_effective_subtarget(target_struct, subtarget_struct)
154
+ if subtarget_struct.aliashtmldir == ""
155
+ if subtarget_struct.aliashtmlfile == ""
156
+ htmlfpath = nil
157
+ else
158
+ htmlfpath = subtarget_struct.aliashtmlfile
159
+ end
160
+ else
161
+ htmlfpath = File.join(subtarget_struct.aliashtmldir, subtarget_struct.aliashtmlfile)
162
+ end
163
+
164
+ if htmlfpath
165
+ subtarget_struct_x = @env.get_subtarget_by_htmlfile(target_struct.name, htmlfpath)
166
+ else
167
+ subtarget_struct_x = subtarget_struct
168
+ end
169
+
170
+ subtarget_struct_x
171
+ end
172
+
173
+ #
174
+ # 指定されたパートに対応するHTMLファイルパスを得る
175
+ # @param target_struct [Struct] ターゲットストラクト
176
+ # @param subtarget_struct [Struct] サブターゲットストラクト
177
+ # @param kind [Symbol] :partA パートA :partB パートB
178
+ def get_part_html(target_struct, subtarget_struct, kind)
179
+ subtarget_x = get_effective_subtarget(target_struct, subtarget_struct)
180
+
181
+ path = ""
182
+ case kind
183
+ when :partA
184
+ path = subtarget_x.filedir.partAhtml
185
+ when :partC
186
+ path = subtarget_x.filedir.partChtml
187
+ end
188
+
189
+ path
190
+ end
191
+
192
+ def command_make_md(src_dir, datafile, outputfile, dataop, templatefile, auxhs={})
193
+ @mes.output_info(%Q!command_make_md(#{datafile}, #{outputfile}, #{dataop}, #{templatefile}, #{auxhs}!)
194
+ if src_dir
195
+ datafile = File.join(src_dir, datafile) if datafile
196
+ outputfile = File.join(src_dir, outputfile) if outputfile
197
+ end
198
+ optsx = {}
199
+ optsx["data"] = datafile
200
+ optsx["output"] = outputfile
201
+ optsx["dataop"] = dataop
202
+
203
+ mmt = Mdextab::Makemdtab.new(optsx, @str_variable, @str_static, @obj_by_yaml, @mes)
204
+ if templatefile
205
+ if src_dir
206
+ template_fullpath = File.join(src_dir, @template_dir, templatefile)
207
+ else
208
+ template_fullpath = File.join(@template_dir, templatefile)
209
+ end
210
+ else
211
+ template_fullpath = @default_table_template
212
+ end
213
+
214
+ mmt.make_md2(src_dir, template_fullpath, auxhs)
215
+ mmt.post_process
216
+ end
217
+
218
+ def simple_md2html(inputmd, output_htmlfname)
219
+ @mes.output_info(%Q(pandoc -o #{output_htmlfname} -t html5 #{inputmd}))
220
+ ret = false
221
+ _, _, s = Open3.capture3(%Q(pandoc -o #{output_htmlfname} -t html5 #{inputmd}))
222
+
223
+ if s.exited?
224
+ if s.exitstatus == 0
225
+ ret = true
226
+ else
227
+ @mes.output_error("Can't convert from md to html by pandoc(exit_code=#{s.exitstatus})")
228
+ exit(@mes.ec("EXIT_CODE_CANNOT_CONVERT_FROM_MD_TO_HTML"))
229
+ end
230
+ else
231
+ @mes.output_error("Pandoc exit abnormally")
232
+ exit(@mes.ec("EXIT_CODE_PANDOC_EXIT_ABNORMALLY"))
233
+ end
234
+
235
+ ret
236
+ end
237
+
238
+ def output_html(out_htmlfname, mode, parta, content, partb)
239
+ File.open(out_htmlfname, mode) do |f|
240
+ f.write(parta)
241
+ f.write(content)
242
+ f.write(partb)
243
+ end
244
+ end
245
+
246
+ def md2html(root_outputmd, out_htmlfname, parta, partb)
247
+ tmpdir = File.dirname(out_htmlfname)
248
+ tmpbasename = File.basename(out_htmlfname)
249
+
250
+ content_htmlfname = File.join(tmpdir, tmpbasename + ".tmp")
251
+ unless root_outputmd
252
+ @mes.output_fatal("Can't find file(=#{root_outputmd}")
253
+ exit(@mes.ec("EXIT_CODE_CANNOT_FIND_FILE"))
254
+ end
255
+ @mes.output_debug("root_outputmd=#{root_outputmd}")
256
+ @mes.output_debug("content_htmlfname=#{content_htmlfname}")
257
+ ret = simple_md2html(root_outputmd, content_htmlfname)
258
+ return unless ret
259
+
260
+ ret = simple_md2html(root_outputmd, "x.html")
261
+ unless ret
262
+ tmpf.close(true)
263
+ return
264
+ end
265
+
266
+ content = ""
267
+ @mes.exc_file_read(content_htmlfname) { content = File.readlines(content_htmlfname).join }
268
+ @mes.output_debug("file_read #{content_htmlfname}")
269
+ # @mes.output_debug("content #{content}")
270
+ @mes.exc_file_write(out_htmlfname) { output_html(out_htmlfname, "w", parta, content, partb) }
271
+ @mes.output_debug("file_write #{out_htmlfname}")
272
+ # File.unlink(content_htmlfname)
273
+ end
274
+
275
+ def command_make_html(src_dir, outputfile_md, root_output_md, parta_html, partc_html, out_htmlfname)
276
+ @mes.output_info(%Q!command_makehtml(#{outputfile_md}, #{root_output_md}, #{parta_html} #{partc_html} #{out_htmlfname}!)
277
+ if src_dir
278
+ outputfile_md = File.join(src_dir, outputfile_md) if outputfile_md
279
+ root_output_md = File.join(src_dir, root_output_md) if root_output_md
280
+ parta_html = File.join(src_dir, parta_html) if parta_html
281
+ partc_html = File.join(src_dir, partc_html) if partc_html
282
+ out_htmlfname = File.join(src_dir, out_htmlfname) if out_htmlfname
283
+ end
284
+
285
+ optsx = {}
286
+ m = Mdextab::Mdextab.new(optsx, outputfile_md, root_output_md, @mes)
287
+ m.parse(@obj_by_yaml)
288
+ m.post_process
289
+
290
+ parta = Filex::Filex.check_and_load_file(parta_html, @mes)
291
+ partc = Filex::Filex.check_and_load_file(partc_html, @mes)
292
+ md2html(root_output_md, out_htmlfname, parta, partc)
293
+ end
294
+ end
295
+ end
@@ -0,0 +1,33 @@
1
+ module Md2site
2
+ module Nkfguess
3
+ require "nkf"
4
+
5
+ def self.guess_file(fname, mes)
6
+ str = nil
7
+ mes.exc_file_read(fname) { File.open(fname) {|f| str = f.gets(nil) } }
8
+ if str.nil?
9
+ encoding = nil
10
+ else
11
+ case NKF.guess(str)
12
+ when NKF::JIS
13
+ encoding = "ISO-2022-JP"
14
+ when NKF::EUC
15
+ encoding = "eucJP"
16
+ when NKF::SJIS
17
+ encoding = "CP932"
18
+ when NKF::UTF8
19
+ encoding = "UTF-8"
20
+ when NKF::BINARY
21
+ encoding = "ASCII-8BIT"
22
+ when NKF::ASCII
23
+ encoding = "ASCII-8BIT"
24
+ when NKF::UNKNOWN
25
+ encoding = "ASCII-8BIT"
26
+ else
27
+ encoding = "ASCII-8BIT"
28
+ end
29
+ end
30
+ encoding
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,358 @@
1
+ module Md2site
2
+ #
3
+ # setupサブコマンドクラス
4
+ #
5
+ class Setup
6
+ # WEBサイトへのアクセス待ち時間(秒単位)
7
+ ACCESS_WAIT_SEC = 10
8
+ # ACCESS_WAIT_SEC=5
9
+ # ACCESS_WAIT_SEC=1
10
+
11
+ require "faraday_middleware"
12
+ require "faraday"
13
+ require "date"
14
+ require "open3"
15
+ require "uri"
16
+ require "digest"
17
+ require "messagex"
18
+ require "md2site/statusfile"
19
+ require "md2site/listfile"
20
+
21
+ #
22
+ # 初期化
23
+ # @param env [Env] Envクラスのメソッド
24
+ # @param mes [Messagex] Messagexクラスのインスタンス
25
+ def initialize(env, mes)
26
+ @env = env
27
+ @mes = mes
28
+ @category = @env.category
29
+ @category_x = @env.category_x
30
+ absolute_path_status_file = env.conf_hs["ABSOLUTE_PATH_STATUS_FILE"]
31
+ @url = @env.conf_hs["URL"]
32
+ @res = {}
33
+
34
+ @mes.add_exitcode("EXIT_CODE_BY_EXCEPTION")
35
+ @mes.add_exitcode("EXIT_CODE_EXECUTE_SETUP_BEFORE_UPDATE_HTMLFILES")
36
+ @mes.add_exitcode("EXIT_CODE_CANNOT_FIND_DEST_DIR")
37
+ @mes.add_exitcode("EXIT_CODE_CANNOT_CONVERT_FROM_HTML_TO_MD")
38
+ @mes.add_exitcode("EXIT_CODE_PANDOC_EXIT_ABNORMALLY")
39
+ @status_file = StatusFile.new(absolute_path_status_file, @url, @mes)
40
+ end
41
+
42
+ #
43
+ # サブコマンド実行
44
+ # @param option [String] サブコマンドのオプション
45
+ def execute_subcommand(option)
46
+ case option.name
47
+ when "contentUpdate"
48
+ update_htmlfiles
49
+ when "zcontents"
50
+ dir = @env.get_filepath(option.value)
51
+ unless dir
52
+ @mes.exc_make_directory(option.value) { FileUtils.mkdir_p(option.value) }
53
+ dir = @env.get_filepath(option.value)
54
+ end
55
+ unless dir || FileTest.directory?(dir)
56
+ @mes.output_fatal("Can't find drectory(=#{dir}")
57
+ exit(@mes.ec("EXIT_CODE_CANNOT_FIND_DIRECTORY"))
58
+ end
59
+ get_remote_contents(dir)
60
+ when "getfiles"
61
+ dir = @env.get_filepath(option.value)
62
+ get_remote_file_headers(dir)
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ #
69
+ # リモートサイトのファイル取得
70
+ # @param url [String] 取得先URL
71
+ # @return [Array] 第0要素:Datetime 第1要素:UNIXタイム 第2要素:HTTPボディ
72
+ def get_remote_file(url)
73
+ connection = Faraday.new(url) do |conn|
74
+ conn.use(FaradayMiddleware::FollowRedirects)
75
+ conn.adapter(:net_http)
76
+ end
77
+ @mes.output_debug("url=#{url}")
78
+ res = connection.get(url)
79
+ datetime_str, datetime_unix_time = get_modified_in_datetime_or_date_in_datetime_from_header(res.headers)
80
+ [datetime_str, datetime_unix_time, res.body]
81
+ end
82
+
83
+ #
84
+ # HTTPヘッダの指定フィールドの値を文字列とUNITタイムで取得する
85
+ # @param headers [Hash] HTTPヘッダを表すハッシュ
86
+ # @param key [String] HTTPヘッダのフィールドを指定するキー
87
+ # @return [Array] 第0要素: 指定フィールドの値(String) 第1要素: 指定フィールドの値(UNIXタイム)
88
+ def get_header_value_of_datetime(headers, key)
89
+ @res[key] ||= Regexp.compile(Regexp.escape(key))
90
+ keys = headers.keys.select {|x| @res[key].match?(x.downcase) }
91
+
92
+ if keys.size == 1
93
+ k = keys.first
94
+ s = headers[k]
95
+ begin
96
+ dt = DateTime.httpdate(s)
97
+ unixtime = dt.to_time.to_i
98
+ rescue ArgumentError => e
99
+ @mes.output_exception(e)
100
+ @mes.output_fatal("s=#{s}")
101
+ exit(@mes.ec("EXIT_CODE_BY_EXCEPTION"))
102
+ rescue Error => e
103
+ @mes.output_exception(e)
104
+ @mes.output_fatal("s=#{s}")
105
+ exit(@mes.ec("EXIT_CODE_BY_EXCEPTION"))
106
+ end
107
+ else
108
+ s = nil
109
+ unixtime = nil
110
+ end
111
+ [s, unixtime]
112
+ end
113
+
114
+ #
115
+ # HTTPヘッダのlast-modifiedフィールドの値を文字列とUNITタイムで取得
116
+ # @param headers [Hash] HTTPヘッダを表すハッシュ
117
+ # @return [Array] 第0要素: 指定フィールドの値(String) 第1要素: 指定フィールドの値(UNIXタイム)
118
+ def get_modified_in_datetime_from_header(headers)
119
+ get_header_value_of_datetime(headers, "last-modified")
120
+ end
121
+
122
+ #
123
+ # HTTPヘッダのdateフィールドの値を文字列とUNITタイムで取得
124
+ # @param headers [Hash] HTTPヘッダを表すハッシュ
125
+ # @return [Array] 第0要素: 指定フィールドの値(String) 第1要素: 指定フィールドの値(UNIXタイム)
126
+ def get_date_in_datetime_from_header(headers)
127
+ get_header_value_of_datetime(headers, "date")
128
+ end
129
+
130
+ #
131
+ # HTTPヘッダから時刻を表すlast-modifiedフィールドまたはdateフィールのの値を文字列とUNIXタイムで取得
132
+ # @param headers [Hash] HTTPヘッダを表すハッシュ
133
+ # @return [Array] 第0要素: 指定フィールドの値(String) 第1要素: 指定フィールドの値(UNIXタイム)
134
+ def get_modified_in_datetime_or_date_in_datetime_from_header(headers)
135
+ ary = get_modified_in_datetime_from_header(headers)
136
+ unless ary.all?
137
+ ary = get_date_in_datetime_from_header(headers)
138
+ end
139
+ ary
140
+ end
141
+
142
+ #
143
+ # 指定URLのHTTPヘッダから時刻を表すlast-modifiedフィールドまたはdateフィールのの値を文字列とUNIXタイムで取得
144
+ # @param url [String] HTTPヘッダを取得したいURL
145
+ # @return [Array] 第0要素: 指定フィールドの値(String) 第1要素: 指定フィールドの値(UNIXタイム)
146
+ def get_modified_in_datetime_or_date_in_datetime(url)
147
+ connection = Faraday.new(url) do |conn|
148
+ conn.use(FaradayMiddleware::FollowRedirects)
149
+ conn.adapter(:net_http)
150
+ end
151
+ @mes.output_debug("url=#{url}")
152
+ res = connection.head(url)
153
+ get_modified_in_datetime_or_date_in_datetime_from_header(res.headers)
154
+ end
155
+
156
+ #
157
+ # 時刻を"年月日-時分秒"の形式の文字列にする
158
+ # @param datetime [Datetime] Datetimeクラスのインスタンス
159
+ # @return [String] "年月日-時分秒"の形式の文字列
160
+ def get_datestring(datetime)
161
+ datetime.strftime("%Y%m%d-%H%M%S")
162
+ end
163
+
164
+ #
165
+ # 現在時刻をDatetimeクラスのインスタンスと文字列にする
166
+ # @return [Array] 第0要素: Datetimeクラスのインスタンス 第1要素: "年月日-時分秒"の形式の文字列
167
+ def current_time
168
+ datetime = DateTime.now
169
+ datetimestr = get_datestring(datetime)
170
+ [datetime, datetimestr]
171
+ end
172
+
173
+ #
174
+ # 指定サイトでダウンロード指定された全URLのHTTPヘッダの時刻を取得して一覧をファイルに保存
175
+ # @param dir [String] HTTPヘッダ時刻一覧ファイルの保存先ディレクトリ
176
+ # @return [Array] 第0要素: Datetimeクラスのインスタンス 第1要素: "年月日-時分秒"の形式の文字列
177
+ # @note 一覧を保存するファイルのファイル名はsite-年月日-時分秒.tsvである
178
+ def get_remote_file_headers(dir)
179
+ _, datetimestr = current_time
180
+
181
+ fname = %Q(site-#{datetimestr}.tsv)
182
+ fpath = File.join(dir, fname)
183
+
184
+ @mes.exc_file_write(fpath) do
185
+ File.open(fpath, "w") do |ofile|
186
+ @category_x[:category].each do |_k, v|
187
+ v.each do |_k2, v2|
188
+ filename = v2[@env.htmlfile_index]
189
+ next if v2[@env.alias_htmlfile_index]
190
+
191
+ if %r{/$}.match?(@url)
192
+ file_url = URI.join(@url, filename)
193
+ else
194
+ file_url = URI.join(@url, "/", filename)
195
+ end
196
+ ary = get_modified_in_datetime_or_date_in_datetime(file_url)
197
+ unless ary.all?
198
+ @mes.output_error("Can't find last-modified header from #{@url}")
199
+ end
200
+ v2.concat(ary)
201
+
202
+ ofile.puts(v2.join("\t"))
203
+ end
204
+ end
205
+ end
206
+ end
207
+ @status_file.fname = fname
208
+ @status_file.fpath = fpath
209
+ @status_file.last_datetime = datetimestr
210
+ @status_file.update
211
+ end
212
+
213
+ #
214
+ # 引数で指定したファイルが書込み可能であるように書込み先ディレクトリを作成
215
+ # @param dir [String] ディレクトリ
216
+ # @param filename [String] ファイルへのパス(ファイル名のみも可)
217
+ def prepare_new_write_path(dir, filename)
218
+ dirname = File.dirname(filename)
219
+ if dirname != "."
220
+ dirpath = File.join(dir, dirname)
221
+ @mes.exc_make_directory(dirpath) { FileUtils.mkdir_p(dirpath) }
222
+ basename = File.basename(filename)
223
+ fpath = File.join(dirpath, basename)
224
+ else
225
+ fpath = File.join(dir, filename)
226
+ end
227
+ fpath
228
+ end
229
+
230
+ def get_remote_contents_sub(target_hash, listfile, last_contents_path)
231
+ target_hash.each do |_, target_def|
232
+ filename = target_def[@env.htmlfile_index]
233
+ next if target_def[@env.alias_htmlfile_index]
234
+
235
+ if %r{/$}.match?(@url)
236
+ file_url = URI.join(@url, filename)
237
+ else
238
+ file_url = URI.join(@url, "/", filename)
239
+ end
240
+ remote_datetime_str, remote_datetime_unixtime, content = get_remote_file(file_url)
241
+ unless [remote_datetime_str, remote_datetime_unixtime].all?
242
+ @mes.output_error("Can't get content from #{file_url}")
243
+ listfile.add([filename, remote_datetime_str, remote_datetime_unixtime, nil])
244
+
245
+ sleep(ACCESS_WAIT_SEC)
246
+ next
247
+ end
248
+ fpath = prepare_new_write_path(last_contents_path, filename)
249
+
250
+ @mes.exc_file_write(fpath) do
251
+ File.open(fpath, "w") do |ofile|
252
+ if content
253
+ ofile.puts(content)
254
+ end
255
+ end
256
+ end
257
+ listfile.add([filename, remote_datetime_str, remote_datetime_unixtime, Digest::MD5.hexdigest(content)])
258
+ end
259
+ end
260
+
261
+ def get_remote_contents(dir)
262
+ _, datetimestr = current_time
263
+
264
+ @mes.output_info("dir=#{dir}")
265
+ @mes.output_info("datetimestr=#{datetimestr}")
266
+
267
+ last_contents_path = File.absolute_path(File.join(dir, datetimestr))
268
+ @mes.exc_make_directory(last_contents_path) { FileUtils.mkdir_p(last_contents_path) }
269
+
270
+ lf = ListFile.new(last_contents_path, @mes)
271
+ @category_x[:category].each do |_, target_hash|
272
+ get_remote_contents_sub(target_hash, lf, last_contents_path)
273
+ end
274
+ lf.close
275
+ @status_file.last_contents_path = last_contents_path
276
+ @status_file.update
277
+ end
278
+
279
+ def update_htmlfiles_subtarget(subtarget, src_fpath)
280
+ dest_fpath = prepare_new_write_path(@env.absolutepath_root, subtarget.filedir.html_input)
281
+ unless dest_fpath
282
+ dir = File.dirname(subtarget.filedir.html_input)
283
+ path = File.join(@env.absolutepath_root, dir)
284
+ @mes.exc_make_directory(path) { FileUtils.mkdir_p(path) }
285
+ dest_fpath2 = prepare_new_write_path(@env.absolutepath_root, subtarget.filedir.html_input)
286
+ if dest_fpath2
287
+ dest_fpath = dest_fpath2
288
+ else
289
+ @mes.output_fatal("Can't find dest dir(#{path})")
290
+ exit(@mes.ec("EXIT_CODE_CANNOT_FIND_DEST_DIR"))
291
+ end
292
+ end
293
+
294
+ @mes.exc_file_copy(src_fpath, dest_fpath) { FileUtils.cp(src_fpath, dest_fpath) }
295
+ @mes.output_info("HtmlUtils.divideHtml dest_fpath=#{dest_fpath}")
296
+ ary = HTMLUtils.new(dest_fpath, @mes).divide_html
297
+ dir = File.dirname(dest_fpath)
298
+ (0..2).each do |x|
299
+ ofname = File.join(dir, %Q(#{x}.html))
300
+ @mes.exc_file_write(ofname) { File.open(ofname, "w") {|f| f.puts(ary[x]) } }
301
+ end
302
+ in_html = File.join(dir, %Q(1.html))
303
+ unless File.exist?(in_html)
304
+ @mes.output_fatal("Can't find file(=#{in_html}")
305
+ exit(@mes.ec("EXIT_CODE_CANNOT_FIND_FILE"))
306
+ end
307
+ out_md = prepare_new_write_path(@env.absolutepath_root, subtarget.filedir.input_md)
308
+ simple_html2md(in_html, out_md)
309
+
310
+ path = File.join(@env.absolutepath_root, subtarget.workDir)
311
+ @mes.exc_make_directory(subtarget.workDir) { FileUtils.mkdir_p(path) }
312
+ end
313
+
314
+ def update_htmlfiles
315
+ if @status_file.nil? || @status_file.last_contents_path.nil? || @status_file.last_contents_path.empty?
316
+ @mes.output_info("@status_file=#{@status_file}")
317
+ unless @status_file.nil?
318
+ @mes.output_info("@status_file.last_contents_path=#{@status_file.last_contents_path}")
319
+ end
320
+ exit(@mes.ec("EXIT_CODE_EXECUTE_SETUP_BEFORE_UPDATE_HTMLFILES"))
321
+ else
322
+ @category.each do |_name, category_struct|
323
+ category_struct.subTargets.each do |_k, v|
324
+ next unless v.aliashtmlfile.empty?
325
+ filename = v.htmlfile
326
+ next if filename.empty?
327
+
328
+ src_fpath = File.join(@status_file.last_contents_path, filename)
329
+ unless File.exist?(src_fpath)
330
+ @mes.output_info("#{src_fpath} doesn't exist")
331
+ next
332
+ end
333
+ update_htmlfiles_subtarget(v, src_fpath)
334
+ end
335
+ end
336
+ end
337
+ end
338
+
339
+ def simple_html2md(input_htmlfname, outputmd)
340
+ ret = false
341
+ _, _, s = Open3.capture3(%Q(pandoc -o #{outputmd} -t markdown #{input_htmlfname}))
342
+
343
+ if s.exited?
344
+ if s.exitstatus == 0
345
+ ret = true
346
+ else
347
+ @mes.output_error("Can't convert from html to md by pandoc(IN:#{input_htmlfname} OUT:#{outputmd}(exit_code=#{s.exitstatus})")
348
+ exit(@mes.ec("EXIT_CODE_CANNOT_CONVERT_FROM_HTML_TO_MD"))
349
+ end
350
+ else
351
+ @mes.output_error("Pandoc exit abnormally")
352
+ exit(@mes.ec("EXIT_CODE_PANDOC_EXIT_ABNORMALLY"))
353
+ end
354
+
355
+ ret
356
+ end
357
+ end
358
+ end