[Hiki-dev:00477] history.rb - plugin to show revision history (with cvs/svn)

Back to archive index

Hajime BABA baba.****@nifty*****
2003年 11月 16日 (日) 22:50:02 JST


cvsプラグイン(あるいはsvnプラグイン)を用いてデータの編集履歴管理を
しているときに、編集履歴を参照できるプラグイン history.rb を作成し
ました。一週間ほど手元で試していましたが、それほど問題もなさそうな
ので添付しておきます。よろしければお試し下さい。なお、一覧の出力形
式は WiLiKi の編集履歴を参考にさせていただきました。
http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi


 From: Kazuhiko <kazuh****@fdiar*****>
 Subject: [Hiki-dev:00467] Re: ページ削除について
 Date: Fri, 14 Nov 2003 20:46:48 +0900

 > # cvs プラグインで cvsweb と連係させるような機能を実装したいなぁと思って
 > # いたことを思い出したのは内緒...

たぶん、メニューで
  menu << %Q!<a accesskey="v" href="http://myhost/cgi-bin/viewcvs/#{@page.escape}">ViewCVS</a>!
とかするのでいいんじゃないでしょうか(べたですが)。なので、
history.rb はあくまで簡易版という事で機能的に割りきってます。

#なお、
# > # "NameError(undefined method `escape' for #): body_leave_proc"
#のエラーは、このプラグインの作成のときに起こりました。

--
Hajime BABA / 馬場 肇
baba.****@nifty*****


-------------- next part --------------
=begin

== plugin/history.rb - CVS の編集履歴を表示するプラグイン

  Copyright (C) 2003 Hajime BABA <baba.****@nifty*****>
  $Id: history.rb,v 1.10 2003/11/15 13:17:16 baba Exp $
  You can redistribute and/or modify this file under the terms of the LGPL.

=== 使い方

* Hiki の cvs プラグイン (あるいは svn プラグイン) を利用している
  ことが前提条件です。

* その上で、Hiki のプラグインディレクトリにコピーすれば、
  上部メニューに「編集履歴」が現れて使えるようになります。

=== 詳細

* 以下の三つのプラグインコマンドが追加されます。
    * history       ページの編集履歴の一覧を表示
    * history_src   あるリビジョンのソースを表示
    * history_diff  任意のリビジョン間の差分を表示
  実際には、
    $cgi_name?c=history;p=FrontPage や
    $cgi_name?c=plugin;plugin=history_diff;p=FrontPage;r=2
  のように使用します。

* 履歴にはブランチ等が現れないことを前提にしています。

* Subversion 対応は適当です(僕が使っていないので)。

* プラグイン作成の作法がよくわかってないので、どなたか直してください。

=== SEE ALSO

* 一覧の出力形式は WiLiKi の編集履歴を参考にさせていただきました。
  http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi

=end

def history_label
  '編集履歴'
end

def history
  h = Hiki::History::new(@cgi, @db)
  h.history
end

def history_src
  h = Hiki::History::new(@cgi, @db)
  h.history_src
end

def history_diff
  h = Hiki::History::new(@cgi, @db)
  h.history_diff
end

add_body_enter_proc(Proc.new do
  if $repos_root then
    add_plugin_command('history', history_label, {'p' => true})
  else
    ''
  end
end)

module Hiki
  class History < Command
    private

    def history_repos_type
      'cvs' # or 'svn"
    end

    def history_repos_root
      $repos_root # hiki.conf
    end

    def history_label
      '編集履歴'
    end

    def history_th_label
      #  ['Rev', 'Time(GMT)', 'Changes', 'Operation', 'Log']
      ['Rev', '時刻(GMT)', '変更', '操作', 'ログ']
    end

    def history_not_supported_label
      '現在の設定では編集履歴はサポートされていません。'
    end

    def history_diffto_current_label
      '現在のバージョンとの差分を見る'
    end

    def history_backto_summary_label
      '編集履歴ページに戻る'
    end

    # Subroutine to invoke external command using `` sequence.
    def history_exec_command (cmd_string)
      cmdlog = ''
      oldpwd = Dir.pwd
      begin
	Dir.chdir( "#{$pages_path}" )
	# うーん... まあとりあえず。
	cmdlog = `#{cmd_string}`
      ensure
	Dir.chdir( oldpwd )
      end
      cmdlog
    end

    # Subroutine to output proper HTML for Hiki.
    def history_output (s)
      # Imported codes from hiki/command.rb::cmd_view()
      parser = Parser::new
      tokens = parser.parse( s )
      formatter = HikiFormatter::new( tokens, @db, @plugin )
      @page  = Page::new( @cgi )
      data   = Util::get_common_data( @db, @plugin )
      @plugin.hiki_menu(data, @cmd)
      pg_title =****@plugi*****_name(@p)
      data[:title]      = title( "#{pg_title} - #{history_label}")
      data[:view_title] = "#{pg_title} - #{history_label}"
      data[:body]       = formatter.apply_tdiary_theme(s).sanitize

      @cmd = 'view' # important!!!
      generate_page(data) # private method inherited from Command class
    end


    public

    # Output summary of change history
    def history
      unless history_repos_root then
	return history_output(history_not_supported_label)
      end

      # make command string
      case history_repos_type
      when 'cvs'
	hstcmd = "cvs -Q -d #{history_repos_root} log #{@p.escape}"
      when 'svn'
	hstcmd = "svn log #{@p.escape}"
      else
	return history_output(history_not_supported_label)
      end

      # invoke external command
      cmdlog = history_exec_command(hstcmd)

      # parse the result and make revisions array
      revisions = Array::new()
      case history_repos_type
      when 'cvs'
	cmdlog.split('----------------------------').each do |tmp|
	  if /revision 1.(\d+?)\ndate: (.*?);  author: (?:.*?);  state: (?:.*?);(.*?)?\n(.*)/m =~ tmp then
	    revisions << [$1.to_i, $2, $3, $4]
	  end
	end
      when 'svn' # but not tested...
	cmdlog.split('------------------------------------------------------------------------') do |tmp|
	  if /rev (\d+?): (?:.*?) | (.*?) | (.*?)\n(.*)/m =~ tmp then
	    revisions << [$1.to_i, $2, $3, $4]
	  end
	end
      end

      # construct output sources
      sources = ''
      #  sources << "<pre>\n"
      #  sources << cmdlog
      #  sources << "</pre>\n"
      sources << "\n<table border=\"1\" width=\"100%\">\n"
      sources << " <tr><th rowspan=\"2\">#{history_th_label[0].escapeHTML}</th><th>#{history_th_label[1].escapeHTML}</th><th>#{history_th_label[2].escapeHTML}</th><th>#{history_th_label[3].escapeHTML}</th></tr><tr><th colspan=\"3\">#{history_th_label[4].escapeHTML}</th></tr>\n"
      revisions.each do |rev,time,changes,log|
	#    time << " GMT"
	op = "[<a href=\"#{$cgi_name}#{cmdstr('plugin', \"plugin=history_src;p=#{@p.escape};r=#{rev}\")}\">View</a> this version] "
	op << "[Diff to "
	op << "<a href=\"#{$cgi_name}#{cmdstr('plugin', \"plugin=history_diff;p=#{@p.escape};r=#{rev}\")}\">current</a>" unless revisions.size == rev
	op << " | " unless (revisions.size == rev || rev == 1)
	op << "<a href=\"#{$cgi_name}#{cmdstr('plugin', \"plugin=history_diff;p=#{@p.escape};r=#{rev};r2=#{rev-1}\")}\">previous</a>" unless rev == 1
	op << "]"
	log.gsub!(/=============================================================================/, '')
	log.chomp!
	log = "*** no log message ***" if log.empty?
	sources << " <tr><td rowspan=\"2\">#{rev}</td><td>#{time.escapeHTML}</td><td>#{changes.escapeHTML}</td><td align=right>#{op}</td></tr><tr><td colspan=\"3\">#{log.escapeHTML}</td></tr>\n"
      end
      sources << "</table>\n"

      history_output(sources)
    end

    # Output source at an arbitrary revision
    def history_src
      unless history_repos_root then
	return history_output(history_not_supported_label)
      end

      # make command string
      r =****@cgi*****['r'][0] || '1'
      case history_repos_type
      when 'cvs'
	hstcmd = "cvs -Q -d #{history_repos_root} update -p -r 1.#{r.to_i} #{@p.escape}"
      when 'svn'
	hstcmd = "svn cat -r#{r.to_i} #{@p.escape}"
      else
	return history_output(history_not_supported_label)
      end

      # invoke external command
      cmdlog = history_exec_command(hstcmd)
      cmdlog = "*** no source ***" if cmdlog.empty?

      # construct output sources
      sources = ''
      sources << "<div class=\"section\">\n"
      sources << "<a href=\"#{$cgi_name}#{cmdstr('plugin', \"plugin=history_diff;p=#{@p.escape};r=#{r}\")}\">#{history_diffto_current_label.escapeHTML}</a><br>\n"
      sources << "<a href=\"#{$cgi_name}#{cmdstr('history', \"p=#{@p.escape}\")}\">#{history_backto_summary_label.escapeHTML}</a><br>\n"
      sources << "</div>\n"
      sources << "<pre class=\"diff\">\n"
      sources << cmdlog.escapeHTML
      sources << "</pre>\n"

      history_output(sources)
    end

    # Output diff between two arbitrary revisions
    def history_diff
      unless history_repos_root then
	return history_output(history_not_supported_label)
      end

      # make command string
      r =****@cgi*****['r'][0] || '1'
      r2 =****@cgi*****['r2'][0]
      case history_repos_type
      when 'cvs'
	revopt = "-r 1.#{r.to_i}"
	revopt = "-r 1.#{r2.to_i} -r 1.#{r.to_i}" unless r2.nil? || r2.to_i == 0
	hstcmd = "cvs -Q -d #{history_repos_root} diff -u #{revopt} #{@p.escape}"
      when 'svn'
	revopt = "-r#{r.to_i}"
	revopt = "-r#{r2.to_i} -r#{r.to_i}" unless r2.nil? || r2.to_i == 0
	hstcmd = "svn diff -u #{revopt} #{@p.escape}"
      else
	return history_output(history_not_supported_label)
      end

      # invoke external command
      cmdlog = history_exec_command(hstcmd)
      cmdlog.gsub!(/(?:.*?)---/m, '---') # Get rid of header
      cmdlog = "*** no diff ***" if cmdlog.empty?

      # construct output sources
      sources = ''
      sources << "<div class=\"section\">\n"
      sources << "<a href=\"#{$cgi_name}#{cmdstr('history', \"p=#{@p.escape}\")}\">#{history_backto_summary_label.escapeHTML}</a><br>\n"
      sources << "</div>\n"
      sources << "<pre class=\"diff\">\n"
      sources << cmdlog.escapeHTML
      sources << "</pre>\n"

      history_output(sources)
    end
  end
end


Hiki-dev メーリングリストの案内
Back to archive index