• R/O
  • SSH
  • HTTPS

vxv-tools: Commit


Commit MetaInfo

Revision42 (tree)
Time2009-10-26 05:56:33
Authorsatofumi

Log Message

html 作成に必要なファイルを追加

Change Summary

Incremental Difference

--- script/doxyHtmlUpdate.rb (nonexistent)
+++ script/doxyHtmlUpdate.rb (revision 42)
@@ -0,0 +1,515 @@
1+#!/usr/bin/ruby
2+# Doxygen で出力したページを SourceForge 用に調整するツール
3+# 併せて、RSS, 更新履歴の生成も行う
4+# Satofumi KAMIMURA
5+# $Id$
6+#
7+# \todo RSS のリンクに改行が入るのを修正する
8+
9+require 'find'
10+require 'kconv'
11+require "rss"
12+$KCODE = 'SJIS'
13+
14+
15+# RSS 用の項目データ
16+$articles = Array.new
17+
18+
19+# 設定ファイルがないときの処理
20+if ARGV.size < 1
21+ print "usage:\n\t" + __FILE__ + " <config file>\n\n"
22+ exit(1)
23+end
24+config_file = ARGV[0]
25+
26+# 更新履歴のフレーム幅
27+HistoryWidth = 250
28+
29+# 設定ファイルの内容読み出し
30+class ConfigInformation
31+ attr_reader :index_page, :history_max, :replace_words, :target_page, :strip_path, :history_x, :history_y, :line_size_max, :log_file, :rss_10_file, :rss_20_file, :rss_base, :rss_title, :rss_description, :rss_insert, :find_dox_directory
32+
33+ def loadReplaceWords(io)
34+ while line = io.gets
35+ case line.chomp
36+ when /^\s*$/
37+ # 空行までを読み出す
38+ return
39+
40+ when /^(.+?)\s(.+)$/
41+ @replace_words[$1] = $2
42+ end
43+ end
44+ end
45+
46+ def initialize(file)
47+ @target_page = nil
48+ @index_page = nil
49+ @replace_words = Hash.new
50+ @strip_path = ''
51+ @line_size_max = 20
52+ @log_file = 'history_log.txt'
53+ @rss_10_file = nil
54+ @rss_20_file = nil
55+ @rss_base = 'rss_base_address'
56+ @rss_title = 'rss title'
57+ @rss_description = 'rss description'
58+ @rss_insert = false
59+ @find_dox_directory = "./"
60+
61+ File.open(file) { |io|
62+ while line = io.gets
63+ case line.chomp
64+ when /TargetHtml\s(.+)/
65+ @target_page = $1.split
66+
67+ when /IndexHtml\s(.+)/
68+ @index_page = $1
69+
70+ when /StripFromExamplesPath\s(.+)/
71+ @strip_path = $1
72+
73+ when /IndexHistoryMax\s(\d+)/
74+ @history_max = $1.to_i
75+
76+ when /IndexPosition\s(\d+)x(\d+)/
77+ @history_x = $1.to_i
78+ @history_y = $2.to_i
79+
80+ when /ReplaceList/
81+ loadReplaceWords(io)
82+
83+ when /HistoryLineMax\s(\d+)/
84+ @line_size_max = $1.to_i
85+
86+ when /HistoryLogFile\s(.+)/
87+ @log_file = $1
88+
89+ when /OutputRss10\s(.+)/
90+ @rss_10_file = $1
91+
92+ when /OutputRss20\s(.+)/
93+ @rss_20_file = $1
94+
95+ when /RssBaseUrl\s(.+)/
96+ @rss_base = $1
97+
98+ when /RssTitle\s(.+)/
99+ @rss_title = Kconv.kconv($1, Kconv::UTF8, Kconv::SJIS)
100+
101+ when /RssDescription\s(.+)/
102+ @rss_description = Kconv.kconv($1, Kconv::UTF8, Kconv::SJIS)
103+
104+ when /InsertRss\s[Yy][Ee][Ss]/
105+ @rss_insert = true
106+
107+ when /FindDoxDirectory\s(.+)/
108+ @find_dox_directory = $1
109+ end
110+ end
111+ }
112+ @target_page = (@target_page == nil) ? Array.new : @target_page
113+ @index_page = (@index_page == nil) ? '' : @index_page
114+ end
115+end
116+configs = ConfigInformation.new(config_file)
117+
118+
119+# ファイルの置換
120+def updatefile(page, lines)
121+ File.open(page, 'w') { |io|
122+ io.write(lines)
123+ }
124+end
125+
126+
127+# 文字毎のエンコード
128+def hexEncode(line, type)
129+
130+ encoded = ''
131+ line.each_byte { |ch|
132+ if ch.chr =~ /[a-zA-Z:]/
133+ case type
134+ when 0
135+ encoded += '&#' + ch.to_s(10) + ';'
136+
137+ when 1
138+ encoded += '%' + ch.to_s(16)
139+
140+ when 2
141+ encoded += '&#x' + ch.to_s(16) + ';'
142+ end
143+ else
144+ encoded += ch.chr
145+ end
146+ }
147+ encoded
148+end
149+
150+
151+# メールアドレスのエンコード
152+def encodeMailAddress(line)
153+
154+ if line =~ /(mailto:)(.+)">(.+)/
155+ hexEncode($1, 0) + hexEncode($2, 1) + '">' + hexEncode($3, 2)
156+ #$1 + hexEncode($2, 1) + '" >' + hexEncode($3, 2)
157+ else
158+ line
159+ end
160+end
161+
162+
163+# ページ毎に置換処理を行う
164+configs.target_page.each { |page|
165+ updated = false
166+
167+ # ファイルの読み出し
168+ lines = File.read(page)
169+
170+ # メールアドレスの置換
171+ match_pattern = /<a href="(mailto:[^%].+)<\/a>/
172+ while lines.match(match_pattern)
173+ replace = '<a href="' + encodeMailAddress($1) + '</a>'
174+ lines.sub!(match_pattern, replace)
175+ updated = true
176+ end
177+
178+ # 任意タグの置換
179+ configs.replace_words.each { |key, words|
180+ if lines.match(key)
181+ lines.gsub!(key, words)
182+ updated = true
183+ end
184+ }
185+
186+ # ファイルの置換
187+ if updated
188+ updatefile(page, lines);
189+ print 'update "' + page + "\"\n"
190+ end
191+}
192+
193+
194+# ページ情報の処理クラス
195+class PageInformation
196+ attr_reader :name, :mtime
197+
198+ def initialize(fname)
199+ @name = fname
200+ @mtime = File.mtime(fname).tv_sec
201+ end
202+end
203+
204+
205+# RSS ファイルの生成
206+def createRss(type, fname, rss_settings)
207+
208+ rss = RSS::Maker.make(type) do |maker|
209+ # !!! ひどいな...。fname, basename の扱いを確認すべき
210+ maker.channel.about = rss_settings['base'] + File.basename(fname)
211+ maker.channel.title = rss_settings['title']
212+ maker.channel.description = rss_settings['description']
213+ maker.channel.link = rss_settings['base']
214+
215+ maker.items.do_sort = true
216+
217+ items_num = 0;
218+ $articles.each { |article|
219+ maker.items.new_item do |item|
220+ # !!! article を代入するように変更する
221+ item.link = rss_settings['base'] + article['link']
222+ item.title = article['title']
223+ item.date = article['date']
224+ item.description = article['description']
225+ end
226+
227+ items_num += 1
228+ if items_num >= 15
229+ break
230+ end
231+ }
232+ end
233+
234+ File.open(fname, 'w') { |io|
235+ io << rss.to_s
236+ }
237+end
238+
239+# 更新履歴メモの作成
240+def insertUpdateMemo(logfile, line_size_max)
241+
242+ if !File.exist?(logfile)
243+ return '';
244+ end
245+
246+ out = ''
247+ File.open(logfile) { |io|
248+ # パースフォーマット
249+ # -----+-----
250+ # リンク
251+ # タイトル
252+ # 詳細
253+ # "\n"
254+
255+ # !!! 実装、適当すぎだ!
256+ last_date = Time.now
257+ parse_index = 0
258+ link = nil
259+ title = nil
260+ messages = ''
261+ while line = io.gets
262+ case line
263+ when /---+---/
264+ out += '<hr align="left" size="1" width="90%">'
265+
266+ when /^(\d\d\d\d)[\/-](\d\d)[\/-](\d\d)$/
267+ last_date = Time.local($1, $2, $3)
268+ if out != ''
269+ out += '<br>'
270+ end
271+ out += $1 + '-' + $2 + '-' + $3
272+ else
273+
274+ case parse_index
275+ when 0
276+ # リンク
277+ link = line.chomp
278+ parse_index += 1
279+
280+ when 1
281+ # タイトル
282+ title = Kconv.kconv(line, Kconv::UTF8, Kconv::SJIS).chomp
283+ parse_index += 1
284+
285+ else
286+ # 詳細
287+ messages += Kconv.kconv(line, Kconv::UTF8, Kconv::SJIS).chomp
288+ end
289+
290+ # !!! 現状は、詳細が改行で終わっているときは、処理されない
291+ if line.chomp == ''
292+ # 項目のリンク作成
293+ if link && title
294+ if messages.chomp == ''
295+ messages = Kconv.kconv('説明なし', Kconv::UTF8, Kconv::SJIS)
296+ end
297+ out += '- <a class="el" href="' + link + '">' + title + '</a><br>'
298+ out += '<div class="log_space">' + messages + '</div><br>'
299+
300+ # !!! ここでグローバル変数を使うんかい!
301+ date = last_date
302+ $articles << { 'link' => link, 'title' => title, 'date' => date, 'description' => messages }
303+ end
304+
305+ parse_index = 0
306+ link = nil
307+ title = nil
308+ messages = ''
309+ end
310+ end
311+ end
312+ }
313+
314+ '<table class="main" border="0" cellpadding="0" cellspacing="0" width="100%">' + "\n" + '<tbody><tr><td><strong>' + Kconv.kconv('更新履歴', Kconv::UTF8, Kconv::SJIS) + '</strong><div class="log_frame">' + out + '<br><br><br><br><br><br><br><br><br><br><br><br> </td></tr></tbody></table>'
315+end
316+
317+
318+# 更新ページ履歴の作成
319+def insertUpdateHistory(history_max, find_path)
320+
321+ # 対象ページの検索を行う
322+ files = Array.new
323+ Find.find(find_path) { |name|
324+ Find.prune if (name =~ /.svn/ || name =~ /output_html/ || name =~ /~$/)
325+ if ! File.file?(name)
326+ next
327+ end
328+
329+ files.push(PageInformation.new(name))
330+ }
331+ files.sort! { |a, b| a.mtime <=> b.mtime }
332+ files.reverse!
333+
334+ # page 情報を新しい順に処理する
335+ pages_counter = 0
336+ update_days = Array.new
337+ files.each { |info|
338+ # ファイル毎に \page の情報を取得する
339+ lines = File.read(info.name);
340+ lines.each_line { |line|
341+ if line =~ /^\s+\\page\s+(.+?)\s+(.+)/
342+ link = $1
343+ #title = Kconv.kconv($2, Kconv::UTF8, Kconv::SJIS)
344+ title = $2
345+ pages_counter += 1
346+
347+ # 更新履歴のタグを作る
348+ date = Time.at(info.mtime).strftime("%Y-%m-%d")
349+ href = '<a class=el href="' + link + '.html">' + title + '</a>'
350+ update_days.push([date, href])
351+ end
352+ }
353+ break if pages_counter >= history_max
354+ }
355+
356+ # 整形して返す
357+ last_date = ''
358+ output = ''
359+ update_days.each { |date, href|
360+ if last_date != date
361+ if output != ''
362+ output += '<br>';
363+ end
364+ output += date + '<hr align="left" size="1" width="90%">'
365+ last_date = date
366+ end
367+ output += '&nbsp;&nbsp;- ' + href + '<br>'
368+ }
369+
370+ return '<strong>' + Kconv.kconv('最近変更されたページ', Kconv::UTF8, Kconv::SJIS) + '</strong><br><div class="history_frame">' + output + '</div>'
371+end
372+
373+
374+# トップページに更新履歴を追加する
375+configs.index_page.each { |page|
376+ lines = File.read(page)
377+
378+ # 本文中に "TWOCOLUMN" があれば、それを検出するようにする
379+ # !!!
380+
381+ first_detected = false
382+ replace_lines = ''
383+ lines.each_line { |line|
384+ # 本文中に、"TWOCOLUMN" があれば、それを2段組の開始位置とする
385+ # Doxygen 処理後は、"&lt;twocolumn&gt;<ul>" になっている
386+ # !!! あると仮定して実装する
387+ if (! first_detected) && (line =~ /TWOCOLUMN/)
388+ first_detected = true
389+ replace_lines += "<table width=\"100%\"><tbody><tr valign=\"top\"><td valign=\"top\" width=\"60%\">\n"
390+ line = '';
391+ end
392+
393+ # TWOCOLUMN_END までの行を生成ページの末尾と判断する
394+ if line =~ /TWOCOLUMN_END/ && first_detected
395+ line.sub!(/TWOCOLUMN_END/, '')
396+ replace_lines += "</td><td valign=\"top\" width=\"40%\">\n"
397+
398+ # 更新メッセージの追加
399+ replace_lines += insertUpdateMemo(configs.log_file, configs.line_size_max) + "\n"
400+
401+ # ページ更新履歴の追加
402+ if configs.history_max > 0
403+ # 項目を表示する可能性があるならば、表示させる
404+ replace_lines += '<br><br>'
405+ replace_lines += insertUpdateHistory(configs.history_max, configs.find_dox_directory) + "\n"
406+ end
407+ replace_lines += "</td></tr></tbody></table>\n"
408+ end
409+ replace_lines += line
410+
411+ # 指定がなければ、最初の ^</div> を、2段組の開始位置と判断する
412+ #if (! first_detected) && (line =~ /^<\/div>/)
413+ #first_detected = true
414+ #replace_lines += "<table width=100%><tr><td width=60%>\n"
415+ #end
416+ }
417+
418+ # TWOCOLUMN でない場合に、RSS を追加するために、insertUpdateMemo を呼び出す
419+ # !!! ひどすぎる...
420+ if ! first_detected
421+ insertUpdateMemo(configs.log_file, configs.line_size_max)
422+ end
423+
424+ # !!! つか、実装が適当すぎだろ!
425+ # 指定があれば、RSS ファイルを出力する
426+ rss_settings = { 'base' => configs.rss_base, 'title' => configs.rss_title, 'description' => configs.rss_description }
427+
428+ if configs.rss_10_file
429+ createRss('1.0', configs.rss_10_file, rss_settings)
430+ if configs.rss_insert
431+ replace_lines.sub!(/<\/title>\n/, "</title>\n" + '<link rel="alternate" type="application/rss+xml" title="RSS 1.0" href="' + rss_settings['base'] + File.basename(configs.rss_10_file) + '">' + "\n")
432+ end
433+ end
434+ if configs.rss_20_file
435+ createRss('2.0', configs.rss_20_file, rss_settings)
436+ if configs.rss_insert
437+ replace_lines.sub!(/<\/title>\n/, "</title>\n" + '<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="' + rss_settings['base'] + File.basename(configs.rss_20_file) + '">' + "\n")
438+ end
439+ end
440+
441+ # ファイルの置換
442+ File.open(page, 'w') { |io|
443+ io.write(replace_lines)
444+ }
445+}
446+
447+
448+# Examples から、共通 PATH を取り除く
449+# !!! 要、エラー処理。場所の指定がなかった場合について
450+examples_file = File.dirname(configs.index_page) + '/examples.html'
451+begin
452+ lines = File.read(examples_file);
453+rescue => exc
454+ensure
455+ lines = ''
456+end
457+
458+match_pattern = '">' + configs.strip_path
459+update = false
460+if lines.match(match_pattern)
461+ replace = '">'
462+ lines.gsub!(match_pattern, replace)
463+ updated = true
464+end
465+# ファイルの更新
466+if updated
467+ updatefile(examples_file, lines);
468+ print 'update "' + examples_file + "\"\n"
469+end
470+
471+# *-examples.html から、共通パスを取り除く
472+# 対象ページの検索を行う
473+match_pattern = configs.strip_path
474+Find.find('./doxygen_html/') { |name|
475+ if name =~ /.+\.html$/
476+ # 置換処理
477+ lines = File.read(name)
478+ # !!! 改行を読み飛ばす正規表現に置き換える
479+ while lines.match(match_pattern)
480+ lines.sub!(match_pattern, '')
481+ updated = true
482+ end
483+
484+ # ファイルの更新
485+ if updated
486+ updatefile(name, lines);
487+ print 'update "' + name + "\"\n"
488+ end
489+ end
490+}
491+
492+
493+# doxygen.css に設定を追加する
494+css_file = File.dirname(configs.index_page) + '/doxygen.css'
495+File.open(css_file, 'a') { |io|
496+io.print <<-"EOB"
497+.history_frame {
498+ clear:both;
499+ line-height:19px;
500+ padding:4px;
501+ border:solid 2px MediumSlateBlue;
502+}
503+
504+.log_frame {
505+ height:250px;
506+ overflow:auto;
507+ border:solid 2px MediumSlateBlue;
508+ padding:4px;
509+}
510+
511+.log_space {
512+ margin-left: 18px;
513+}
514+EOB
515+}
Added: svn:keywords
## -0,0 +1 ##
+Id Date Author Rev URL
\ No newline at end of property
Show on old repository browser