cpprefjpを支える技術

@cpp_akira, @melponn

目次

  • cpprefjpの概要
  • Google Sitesの問題点
  • GitHubへの移行
    • Google SitesからGitHubへ(@cpp_akira)
    • GitHubからGoogle Sitesへ(@melponn)

cpprefjpの概要

  • cpprefjpの概要
  • Google Sitesの問題点
  • GitHubへの移行
    • Google SitesからGitHubへ(@cpp_akira)
    • GitHubからGoogle Sitesへ(@melponn)

cpprefjpの概要

  • こんなページです

cpprefjpの概要

  • 標準C++のリファレンスサイト
  • Google Sitesを使ってる
    • Google製のWiki。
  • 2014年3月現在で2,000ページ超。

cpprefjpの概要

  • 現在、ページを作成・編集するためにGoogle Sitesを直接叩いているわけではない。
  • cpprefjpの裏側がどうなっているのかについて話します。

Google Sitesの問題点

  • cpprefjpの概要
  • Google Sitesの問題点
  • GitHubへの移行
    • Google SitesからGitHubへ(@cpp_akira)
    • GitHubからGoogle Sitesへ(@melponn)

Google Sitesの問題点

cpprefjpのUI

Google Sitesの問題点

  • Google Sitesでリファレンスを書くのは、けっこう大変だった。
    • 作業者が統一的な書き方をする上で、グラフィカルな操作が邪魔だった。
    • マウスでポチポチ押してコードのフォントを直していくのがしんどかった。
    • シンタックスハイライトがないため見づらかった。

GitHubへの移行

  • cpprefjpの概要
  • Google Sitesの問題点
  • GitHubへの移行
    • Google SitesからGitHubへ(@cpp_akira)
    • GitHubからGoogle Sitesへ(@melponn)

作業環境をGitHubに移行した

  • プレーンテキストで書きたい!
    • 記法を統一するため
    • バージョン管理しやすくするため
  • → MarkdownをGitHubリポジトリで管理することにした。

移行は作業環境のみ

  • Google Sitesはそのままにした。
    • この時点で既に1200ページ以上あり、これらページを行方不明にするのは良くない。
  • GitHubで書いたMarkdownを、自動的にHTMLに変換してGoogle Sitesに同期する仕組みを作った。

移行ツール(初回のみ)

cpprefjpからMarkdownへ変換

移行ツール(運用中)

Markdownからcpprefjpへ変換

Google SitesからGitHubへ(@cpp_akira)

  • cpprefjpの概要
  • Google Sitesの問題点
  • GitHubへの移行
    • Google SitesからGitHubへ(@cpp_akira)
    • GitHubからGoogle Sitesへ(@melponn)

Google SitesからHTMLをダウンロードする

  • Google Apps ScriptというJavaScriptの方言を使った
  • Google SitesのAPIは、1日に呼べる回数が決まっているので、何回かに分けてダウンロードした。

HTMLをMarkdownに変換

  • Ruby 1.9を使って、HTMLを正規表現でがんばってMarkdownに変換した。
  • 完全には自動変換できなかったので、その後全部のリファレンスを手動で手直しした。
  • なのでこのツールは使い捨て。

質問コーナー

  • ここまでで何か質問ありますか?
  • Twitter上での質問とか誰か拾って下さい
  • この先は@melponnに変わります

GitHubからGoogle Sitesへ(@melponn)

  • cpprefjpの概要
  • Google Sitesの問題点
  • GitHubへの移行
    • Google SitesからGitHubへ(@cpp_akira)
    • GitHubからGoogle Sitesへ(@melponn)

目次

  • 動機
  • 作ったもの
    • 変換サーバを支える技術
      • シンタックスハイライト
      • GitHubの差分管理
    • アップロード用Google Apps Scriptを支える技術
      • スクリプトの制限
      • エラー通知

動機

  • 動機
  • 作ったもの
    • 変換サーバを支える技術
      • シンタックスハイライト
      • GitHubの差分管理
    • アップロード用Google Apps Scriptを支える技術
      • スクリプトの制限
      • エラー通知

当時のめるぽんについて

  • GitHub移行プロジェクト、@cpp_akira がやってるのを見てるだけだった。
  • GitHubからMarkdownファイルを取得してHTMLにして返すサーバを作るぐらいなら簡単そう。
  • なので、一晩かけて軽い気持ちで簡単な変換サーバを書いてみた。

管理者になってしまった

作ったもの

  • 動機
  • 作ったもの
    • 変換サーバを支える技術
      • シンタックスハイライト
      • GitHubの差分管理
    • アップロード用Google Apps Scriptを支える技術
      • スクリプトの制限
      • エラー通知

作ったもの

  • 変換サーバ(andare
    • GitHubからMarkdownファイルを取得
    • それをHTMLにして返す
  • アップロード用Google Apps Script
    • 変換サーバにアクセスしてHTMLを取得
    • Google Sitesに毎日アップロードする

移行ツール(運用中)

Markdownからcpprefjpへ変換

変換サーバを支える技術

  • 動機
  • 作ったもの
    • 変換サーバを支える技術
      • シンタックスハイライト
      • GitHubの差分管理
    • アップロード用Google Apps Scriptを支える技術
      • スクリプトの制限
      • エラー通知

変換サーバの特徴

  • Python+Django製
  • MarkdownというPythonのライブラリでHTMLに変換
  • 普通のRESTfulなサーバ
    • GET /contentsで更新するファイル一覧を返す
    • GET /html/:pathsで:pathsのデータをHTMLで返す

シンタックスハイライト

  • 動機
  • 作ったもの
    • 変換サーバを支える技術
      • シンタックスハイライト
      • GitHubの差分管理
    • アップロード用Google Apps Scriptを支える技術
      • スクリプトの制限
      • エラー通知

シンタックスハイライト

  • 「PythonのMarkdownライブラリにシンタックスハイライトあったから入れてみました!」

シンタックスハイライト

  • シンタックスハイライトとは別でリンクや色を付けれるようにした

シンタックスハイライトの仕組み

  • PythonのMarkdownライブラリはコードを渡したら適当にHTMLに変換してくれる仕組み
  • つまり特定の文字を色付けとかできない
  • そこで考えた

シンタックスハイライトの仕組み

  • そうだ力づくで解決しよう(考えてない)
    1. コードから修飾したい文字列を探してランダムな文字列を埋め込む
    2. HTMLに変換する
    3. 最初に使ったランダムな文字列を検索して適当なタグに置き換える

シンタックスハイライトの仕組み

  • シンタックスハイライト前のコード
      
        int main() {
    std::vector<int> v;
    v.push_back(10);
}
  • このコードのpush_backを赤文字にしたい

シンタックスハイライトの仕組み

  • push_backの前後にランダムな文字列を埋め込む
      
        int main() {
    std::vector<int> v;
    v.Yg88HuTPpush_backYg88HuTP(10);
}

シンタックスハイライトの仕組み

  • HTMLに変換する
      
        <span ...>int</span> main() {
    std::vector&lt;<span ...>int</span>&gt; v;
    v.Yg88HuTPpush_backYg88HuTP(<span ...>10</span>);
}

シンタックスハイライトの仕組み

  • ランダムな文字列を適切なタグにする
      
        <span ...>int</span> main() {
    std::vector&lt;<span ...>int</span>&gt; v;
    v.<span style="color:red">push_back</span>(<span ...>10</span>);
}

シンタックスハイライトの仕組み

  • 結果
      
        int main() {
    std::vector<int> v;
    v.push_back(10);
}

なぜ〜という方法でやらないのか?

  • 変換後のHTMLを置換するだけだと…
    • classやspanを強調表示するとHTMLがグチャグチャになる
  • ランダムでない文字列を埋め込むと…
    • その文字列がハイライトの対象になる可能性がある

GitHubの差分管理

  • 動機
  • 作ったもの
    • 変換サーバを支える技術
      • シンタックスハイライト
      • GitHubの差分管理
    • アップロード用Google Apps Scriptを支える技術
      • スクリプトの制限
      • エラー通知

GitHubの差分管理

  • 現在2,000ページ超のページがある
  • 毎日全部更新するのは厳しい
  • 更新があったファイルだけ更新させたい
  • でも更新があるかを手動で調べるのは面倒
  • そうだGitHubを使おう

GitHubの差分管理

  • サーバ内にcpprefjpのリポジトリをcloneしておく
  • cpprefjpリポジトリには2つローカルブランチを作っておく
    • cpprefjpの最新版を置いておくmasterブランチ
    • Google Sitesに上がっている最新版を置いておくsiteブランチ
    • masterブランチは常にsiteブランチと同じか進んでいる状態になる

GitHubの差分管理

GitHubの差分管理

  • masterブランチsiteブランチの違いを見れば更新ファイルが分かる
      
        $ git diff --name-status site master
M implementation.md
A reference/vector.md
D reference/memory.md
  • Google Sitesを更新したらmasterブランチsiteブランチへマージ

GitHubの差分管理

GitHubの差分管理

GitHubの差分管理

質問コーナー

  • ここまでで何か質問ありますか?
  • Twitter上での質問とか誰か拾って下さい
  • もう少しで終わります

アップロード用Google Apps Scriptを支える技術

  • 動機
  • 作ったもの
    • 変換サーバを支える技術
      • シンタックスハイライト
      • GitHubの差分管理
    • アップロード用Google Apps Scriptを支える技術
      • スクリプトの制限
      • エラー通知

アップロード用Google Apps Scriptを支える技術

  • Google SitesにHTMLをアップロードするためのスクリプト
  • Google Sitesを更新するにはGoogle Apps Scriptを使わないといけない
  • 言語的にはJavaScript
  • とてもつらかった

スクリプトの制限

  • 動機
  • 作ったもの
    • 変換サーバを支える技術
      • シンタックスハイライト
      • GitHubの差分管理
    • アップロード用Google Apps Scriptを支える技術
      • スクリプトの制限
      • エラー通知

スクリプトの制限

  • 制限1.実行時間は5分まで
    • 1ファイルを更新するのに5秒ぐらい掛かる
    • 1回の実行で60ファイルぐらいしか更新できない
      • →どこまで更新したかをストレージに保存
      • →4分過ぎたら次のタイマーを仕掛けて終了
      • →次の実行では中断したところから再開
      • 解決!

スクリプトの制限

  • そう思っていた時期が僕にもありました…
  • 制限2.ストレージの1つのキーは9キロバイトまで
    • 実行時の情報(JSON文字列)を格納したら溢れた
    • 数千ファイルを更新する場合には数十キロは欲しい
    • それぞれのファイルが更新済みかの情報が必要
      • →JSON文字列を自動的にぶった切って複数のキーに格納
      • →取り出す時は自動的に結合して取得

エラー通知

  • 動機
  • 作ったもの
    • 変換サーバを支える技術
      • シンタックスハイライト
      • GitHubの差分管理
    • アップロード用Google Apps Scriptを支える技術
      • スクリプトの制限
      • エラー通知

エラー通知

  • エラーを放置するのは良くない
  • スクリプトのエラーはGitHubのIssueに自動的に登録される
  • 次の実行で変換エラーが無くなったら自動的に閉じられる
  • こんな感じ

エラー通知

  • 一時的なエラーの可能性があるので失敗しても何度かリトライ
  • エラーのあったファイルを変換サーバにPOST
  • あとは変換サーバ側でいい感じにIssue登録してくれる

まとめ

  • Google Sitesでリファレンスを書くのは大変だった
  • cpprefjpの移行も大変だった
  • おかげで運用は楽になった

質問コーナー

  • ここまでで何か質問ありますか?
  • Twitter上での質問とか誰か拾って下さい
  • これが最後のチャンスですよ!

質問コーナー

  • 時間がない場合は以下の方法で
    • Twitterで質問する
    • 後で@cpp_akiraに聞く
    • 後で@melponnを問い詰める
    • 君が!泣くまで!問い詰めるのをやめないっ!

ありがとうございました!

Important contact information goes here.


Twittercpp_akira, melponn

GitHubfaithandbrave, melpon