2013年8月24日 星期六

[Linux] 讓 Gitweb 支援 Markdown 顯示 @ Ubuntu 12.04

Gitweb & Markdown

之前同事很常用 Markdown 寫筆記,希望公司用的 gitweb 可以支援,所以我就稍微下海改一下 Perl 啦 XD 在改之前也有上網查了一下,其實 gitweb 本身已經有一個架構可以展現 repo/READM.html 的功能,其實搭配 git 可以弄成每次 project commit 後,自動將某個 markdown 檔案產生對應的 HTML 來用。

可在 /usr/share/gitweb/index.cgi 搜尋 READM.html 找到這片段程式碼:

# If XSS prevention is on, we don't include README.html.
# TODO: Allow a readme in some safe format.
if (!$prevent_xss && -s "$projectroot/$project/README.html") {
        print "<div class=\"title\">readme</div>\n" .
              "<div class=\"readme\">\n";
        insert_file("$projectroot/$project/README.html");
        print "\n</div>\n"; # class="readme"
}


但如此一來就侷限一個 project 只能展現的單一 markdown 檔案,思考一會後,我就選擇依照 gitweb 架構,在處理檔案時的 raw 項目,依樣畫葫做出一個 markdown 選項 XD

做法:
  1. 安裝 markdown ,讓系統支援 markdown 指定
  2. 找尋 sub git_blob_plain 程式碼,複製一份成 sub git_blob_markdown
  3. 找尋 raw 關鍵字,可以在 sub git_blob 中看到選單,只需在 raw 和 HEAD 中間插入 markdown 選單,並註冊 our %actions 處理此動作
  4. 修改 git_blob_markdown ,把它搞成讓 markdown 指令過水一下即可
片段程式碼:

our %actions = (
        ...
        "blob_plain" => \&git_blob_plain,
        "blob_markdown" => \&git_blob_markdown,
        ...
);


git_blob 片段程式碼:

$formats_nav .=
       $cgi->a({-href => href(action=>"history", -replay=>1)},
              "history") .
      " | " .
       $cgi->a({-href => href(action=>"blob_plain", -replay=>1)},
              "raw") .
      " | " .
      $cgi->a({-href => href(action=>"blob_markdown", -replay=>1)},
               "markdown") .
      " | " .

      $cgi->a({-href => href(action=>"blob",
                            hash_base=>"HEAD", file_name=>$file_name)},
              "HEAD");


git_blob_markdown:

sub git_blob_markdown {
        my $type = shift;
        my $expires;
        if (!defined $hash) {
                if (defined $file_name) {
                        my $base = $hash_base || git_get_head_hash($project);
                        $hash = git_get_hash_by_path($base, $file_name, "blob")
                                or die_error(404, "Cannot find file");
                } else {
                        die_error(400, "No file name defined");
                }
        } elsif ($hash =~ m/^[0-9a-fA-F]{40}$/) {
                # blobs defined by non-textual hash id's can be cached
                $expires = "+1d";
        }

        open my $fd, "git ".git_cmd()." cat-file blob $hash | markdown | "
        #open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
                or die_error(500, "Open git-cat-file blob '$hash' failed");

        $type = "text/html";

        # "save as" filename, even when no $file_name is given
        my $save_as = "$hash";
        if (defined $file_name) {
                $save_as = $file_name;
        } elsif ($type =~ m/^text\//) {
                $save_as .= '.txt';
        }

        my $sandbox = $prevent_xss &&
                $type !~ m!^(?:text/[a-z]+|image/(?:gif|png|jpeg))(?:[ ;]|$)!;


        print $cgi->header(
                -charset => 'UTF-8',
                -type => $type,
                -expires => $expires
                );
        local $/ = undef;
        binmode STDOUT, ':raw';
        print <$fd>;
        binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
        close $fd;
}


比較特別的是...我還沒有真的搞懂 gitweb 或 perl 架構,像在 git_blob_markdown 裡頭,原本的架構是用 open my $fd, "-|", ... 繼續的,但我試了很久總搭不起來,就先偷懶用 "git" 代替了 :P 此外,若要增加 markdown 輸出的顯示,如 CSS 等,可以在 git_blob_markdown 下方的 printf <$fd>; 前面,去印一些 CSS 結構囉

沒有留言:

張貼留言