Trac の feed を merge する Yapra の YAML を ERB で作る
タイトルなげぇ。
昨日 Yapra で Trac の timeline feed を 1本に を書いてから、Plagger の assets みたいな仕組みがあればベタに書かなくて済むのかなーとか思ってはいたんだけど、うまい方法も思いつかないので今日とりあえず ERB を使って一つのテンプレートから生成するようにしてみた。
想定しているパターン
- 複数の Trac を運用しているがチェックが面倒なので Timeline の feed を一本化したい
- それぞれの Trac に対してユーザーが複数いるので、各自の横断的な My Tickets の feed を生成したい
場合に役に立つ Yapra 用 YAML を作ります。そのために ERB を利用します。
基本構成
スクリプトと、それを動かしてできた結果のファイルがこんな風に一つのディレクトリに収まる形を想定しています。
.
|-- jane_tickets.yaml My Tickets 用の YAML
|-- john_tickets.yaml My Tickets 用の YAML
|-- merge_trac_timeline.erb timeline 用の YAML のテンプレート
|-- merge_trac_timeline.yaml timeline 用の YAML
|-- prepare.rb スクリプト
|-- smith_tickets.yaml My Tickets 用の YAML
`-- user_tickets.erb 各 user の My Tickets 用の YAML のテンプレート
で、yapra からは
ruby YAPRA_PATH/bin/yapra -d /PATH/TO/ABOVE
という具合にファイルを置いたディレクトリを指定してやると
*.yml
*.yaml
以外は無視して動作してくれます。
スクリプト
users, sites などを適宜調整してください。
#! /usr/bin/ruby
require 'erb'
require 'optparse'
class TracMergePreparer
class FileCannotOpen < Exception; end
def initialize
@path = nil
@name = nil
end
def run
if ( parse_args() )
erb = ERB.new( File.read( @path ), nil, '-' )
if ( @name == 'user_tickets' )
users.each do |user|
File.open( "#{user}_tickets.yaml", 'w' ) do |f|
f.write( erb.result( binding ) )
end
end
else
erb.run( binding )
end
end
end
def parse_args
ret = false
opt = OptionParser.new()
opt.on( '-f', '--format ERB_NAME' ) { |file|
path = File.join( File.dirname( __FILE__ ), file )
if ( File.exist?( path ) )
@path = path
@name = File.basename( file, '.erb' )
ret = true
else
raise FileCannotOpen
end
}
opt.parse!
return ret
end
def users
return %w(
john
smith
jane
)
end
def sites
return %w(
foo
bar
baz
)
end
end # of class
if ( __FILE__ == $0 )
app = TracMergePreparer.new()
app.run()
end
timeline merge 用の YAML を作る
erb はこんな感じ。
<%-
# Usage: ruby prepare.rb -f merge_trac_timeline.erb > merge_trac_timeline.yaml
-%>
- module: RSS::load
config:
url:
<%- sites.each do |site| -%>
- http://HOST/PATH/<%= site %>/timeline?changeset=on&milestone=on&ticket=on&wiki=on&max=50&daysback=90&format=rss
<%- end -%>
- module: Filter::sort
config:
method: date
- module: reverse
- module: Filter::ApplyTemplate
config:
title: '<%%= "[#{item.link.split( /\// )[4]}] #{item.title}" %>'
description: <%%= item.description.gsub( /<[^>]+>/, '' ) %>
content_encoded: <%= item.description %>
- module: RSS::save
config:
title: "multitrack"
link: http://HOST/PATH/TO/FEED
filename: /PATH/TO/FEED
Trac を設置している HOSTNAME や PATH、あと item.link から title に Trac の名前を埋めている部分も PATH の深さによって変わるので注意してください。それぞれ適宜修正のこと。
使い方は上の例で言うと
ruby prepare.rb -f merge_trac_timeline.erb > merge_trac_timeline.yaml
として使う形を考えています。
各ユーザーの My Tickets 用の YAML を作る
<%-
# Usage: ruby prepare.rb -f user_tickets.erb
-%>
- module: RSS::load
config:
url:
<%- sites.each do |site| -%>
- http://HOST/PATH/<%= site %>/report/7?format=rss&USER=<%= user %>
<%- end -%>
- module: Filter::sort
config:
method: date
- module: reverse
- module: Filter::ApplyTemplate
config:
title: '<%%= "[#{item.link.split( /\// )[4]}] #{item.title}" %>'
description: <%%= item.description.gsub( /<[^>]+>/, '' ) %>
content_encoded: <%= item.description %>
- module: RSS::save
config:
title: "<%= user %>'s tickets"
link: http://HOST/PATH/<%= user %>_tickets.xml
filename: /PATH/TO/<%= user %>_tickets.xml
これも必要に応じて修正してください。使い方は
ruby prepare.rb -f user_tickets.erb
を想定しています。この名前はスクリプトの中で決め打っちゃってます。実行すると users に登録してある user の分だけ
#{user}_tickets.yaml
を生成します。
制限
それぞれの Trac に登録されているユーザーが同じでない場合は考えていません。feed が fetch できないとエラーで止まるかも。
また description 内で HTML タグらしき形のものを片っ端から除去しています。読めば分かるように副作用がありますので、注意して使うか、不要ならこの処理は捨てちゃってください。