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 タグらしき形のものを片っ端から除去しています。読めば分かるように副作用がありますので、注意して使うか、不要ならこの処理は捨てちゃってください。

More