require 'fileutils' require 'rdoc/markup/to_html' require 'webrick' class WikiHtml < RDoc::Markup::ToHtml def initialize super @markup.add_special(/\b(([A-Z][a-z]+){2,})\b/, :WIKIWORD) end def handle_special_WIKIWORD(special) "#{special.text}" end end class RDocWiki < WEBrick::HTTPServlet::AbstractServlet TEMPLATE = "\n\n%s\n\n\n%s\n" REVISION = "%s\n
\nMainPage" DISPLAY = "#{REVISION} Edit %s\n" def initialize(server, store) super server @store = File.expand_path store @rcs = File.join @store, 'RCS' @wiki_html = WikiHtml.new FileUtils.mkdir_p @rcs end def add_history_links(body, page, peer, current, head = current) body << " " if current > 1 body << " Revision 1.#{current} by #{peer}" if current != head then body << <<-EOF \n
EOF end if current + 1 == head then body << " " elsif current != head body << " " body << " " end end def check_revision(page, revision) revision =~ /\A1\.(\d+)\z/ current = $1.to_i head, message = current_revision page, current raise WEBrick::HTTPStatus::NotFound if current > head raise WEBrick::HTTPStatus::TemporaryRedirect, "/#{page}" if current == head return message, current, head end def current_revision(page, current = nil) revision = current ? " -r1.#{current}" : '' rlog = `rlog#{revision} #{File.join @store, page}` return nil unless $?.success? rlog =~ /^head: 1\.(\d+)$/ head = $1.to_i rlog =~ /^date: .*\n(.*)/ message = $1 return head, message end def do_GET(request, response) title = nil body = nil uri = request.request_uri if uri.path == '/' then response.set_redirect WEBrick::HTTPStatus::MovedPermanently, 'MainPage' return end page = get_page uri response['Content-Type'] = 'text/html' case uri.query when 'edit' then title = "Editing #{page}" content = get_content page, nil, false body = <<-BODY
BODY when /\Arevision/ then message, current, head = check_revision page, request.query['revision'] title = "Revision #{current} of #{page}" content = get_content page, current body = REVISION % [content] add_history_links body, page, message, current, head when nil then title = page content = get_content page if page == 'WikiCss' then response['Content-Type'] = 'text/css' response.body = content return elsif content then body = DISPLAY % [content, page] current, message = current_revision page add_history_links body, page, message, current else response.set_redirect WEBrick::HTTPStatus::SeeOther, "/#{page}?edit" return end else raise WEBrick::HTTPStatus::NotFound end response.body = TEMPLATE % [title, body] end def do_POST(request, response) uri = request.request_uri page = get_page uri peer = request.peeraddr[2] case uri.query when 'save' then write_content page, request.query['content'], peer when /\Arestore/ then path = File.join @store, page raise WEBrick::HTTPStatus::NotFound unless File.exist? path _, current, head = check_revision page, request.query['revision'] system "co -q -p1.#{current} #{path} > #{path}" system "ci -q -l -m#{peer} -t-#{peer} #{path}" else raise WEBrick::HTTPStatus::NotFound end response.set_redirect WEBrick::HTTPStatus::SeeOther, page end def get_content(page, current = nil, convert = true) path = File.join @store, page return nil unless File.exist? path content = if current then content = `co -q -p1.#{current} #{path}` return nil unless $?.success? content else File.read path end content = @wiki_html.convert content if convert and page != 'WikiCss' content end def get_page(uri) page = uri.path.sub '/', '' raise WEBrick::HTTPStatus::NotFound, "#{uri.path} not found" unless page =~ /\A([A-Z][a-z]+){2,}\z/ page end def write_content(page, content, peer) path = File.join @store, page File.open path, 'w' do |fp| fp.write content end system "ci -q -l -m#{peer} -t-#{peer} #{path}" end end server = WEBrick::HTTPServer.new :Port => 8000 server.mount '/', RDocWiki, '~/.rdocwiki' trap 'INT' do server.shutdown end server.start