Develop and Download Open Source Software

Browse Subversion Repository

Contents of /script/doxyHtmlUpdate.rb

Parent Directory Parent Directory | Revision Log Revision Log


Revision 376 - (show annotations) (download)
Thu Jun 18 16:49:15 2009 UTC (14 years, 9 months ago) by satofumi
File size: 12781 byte(s)
sloader のボーレート変更が不適切だったのを修正
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 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26