株式会社クリアコード > ククログ

ククログ


Debianでパッケージをリリースできるようにしたい - よりDebianらしく

はじめに

以前、オープンソースのカラムストア機能付き全文検索エンジンであるGroongaをDebianに入れるために必要な作業について、最初のとっかかりであるWNPPへのバグ登録の紹介記事を書きました。

今回は、現在進行中であるGroongaのDebianリポジトリ入りを目指す作業の中から、Debianらしいパッケージを用意するときに必要なLintianについて紹介します。

よりDebianらしいパッケージを用意するには

WNPPにバグ登録をしたら次はパッケージを用意する必要があります。Groongaの場合には、すでにパッケージ自体は独自リポジトリで提供していたので、パッケージを作る部分については新たに作業は必要ありませんでした。

問題になるのは、作ったパッケージがDebianのポリシーにきちんと適合しているか、という点です。

パッケージに関する指針はドキュメント化されているので、じっくりと一読すれば作ったパッケージに問題があるかは判断できるでしょう。

ただし、あまりdebパッケージに詳しくない場合にはちょっと大変な作業です。明らかに問題のある箇所は自動的に検出して、必要な修正を行うようにしたいところです。

Lintianとは

上記の目的の達成に役立つのがLintianです。LintianはDebianパッケージを確認し、バグやポリシーに違反している箇所を報告してくれる便利なツールです。debuildでパッケージをビルドしたときに以下のようなログを見たことがあるはずです。これはdebuildがlintianも一緒に実行してくれているからです。

Now running lintian...
W: groonga-plugin-suggest: binary-without-manpage usr/bin/groonga-suggest-create-dataset
W: groonga-plugin-suggest: binary-without-manpage usr/bin/groonga-suggest-httpd
W: groonga-plugin-suggest: binary-without-manpage usr/bin/groonga-suggest-learner
W: groonga-httpd: binary-without-manpage usr/sbin/groonga-httpd
W: groonga-httpd: binary-without-manpage usr/sbin/groonga-httpd-restart
W: groonga-bin: manpage-has-errors-from-man usr/share/man/man1/groonga.1.gz 4070: warning [p 43, 10.0i]: can't break line
W: groonga-bin: binary-without-manpage usr/bin/groonga-benchmark
Finished running lintian.

Debian 新メンテナーガイドには、パッケージのエラーの検証という章が設けられており、Lintian以外のパッケージの問題を確認する方法が紹介されています。

Lintianでパッケージの問題を確認するには

debuildでパッケージをビルドしている場合には、最後にlintianも実行してくれるので個別に実行する必要はありませんが、単体で実行したい場合には次のようにコマンドを実行します。

% lintian -i -I --show-overrides groonga_4.0.0-1_amd64.changes

上記でも良いのですが、さらに詳細をチェックしたい場合もあるでしょう。以下のようにすると、パッケージのアップロードによく使われるmentors.debian.netのレポートと同様の確認を行うことができます。

% lintian -EviIL +pedantic groonga_4.0.0-1_amd64.changes

もしエラーの理由の詳細説明が不要なら、-iは指定しなくても良いでしょう。

% lintian -EvIL +pedantic groonga_4.0.0-1_amd64.changes

上記指定でどんな風なチェック結果になるかは、Groongaの例が参考になるでしょう。

lintianが報告する内容にはタグが必ず含まれています。例えば最初にあげたログだと「binary-without-manpage」が該当します。

どう修正したらいいかのヒントはタグに対応するページがあるので、そちらを参考にすると良いでしょう。例えば、「binary-without-manpage」に対応するページはLintian Tag: binary-without-manpageとなっています。

まとめ

今回はDebianに入れようとしているパッケージがDebianらしいものになっているか確認する方法を紹介しました。 ビルドしたパッケージを新規にDebian入りさせるためには、このあとスポンサーにレビューしてもらわなければなりません。それらについては、またの機会に記事にしたいと思います。

2014-04-03

GitHubのWikiが変更されたら差分付きで通知する方法

一人でWikiを使っている場合はそんなことはありませんが、複数人でWikiを使っている場合はだれかがWikiを変更したらそれを知りたいものです。複数人でWikiを使っている場合は、情報共有のために使うことが多いです。Wikiが変更されたことがわかると、最新の情報を入手することが容易になるため、情報共有という目的を達成しやすくなります。

最新の情報の入手のしやすさという点では「どのように」変更がわかるかが重要です。例えば、次のような変更の知り方があります。下にいくほど最新の情報を入手するための手間が減るので最新の情報を入手しやすくなります。

  • 定期的にWikiの注目しているページをブラウザーで開き、変更がないか確認する。注目しているページが複数ある場合は繰り返し確認する。
  • 定期的にWikiをブラウザーで開き、「最近更新されたページリスト」を確認する。更新されたページのうち、前回確認したときより後に更新されたページを見て変更点を確認する。
  • Wikiに変更があったら通知がくるようにする。通知がきたら↑と同様に変更を確認する。
  • Wikiに変更があったら変更されたページの情報付きで通知がくるようにする。通知がきたら該当ページをブラウザーで開いて変更を確認する。
  • Wikiに変更があったら変更されたページの情報と変更内容付きで通知がくるようにする。通知を見れば変更点がわかるのでブラウザーで確認する必要はない。

なお、複数のWikiがある場合は通知先を一箇所に集約しているかどうかで最新の情報の入手しやすさに影響があります。一箇所に集約している方が最新の情報を入手しやすいです。理由は、集約しているところを確認するだけでよいので手間が減るからです。

ここでは、GitHubのWikiを使っている場合に最新の情報を入手しやすくする方法、つまり、GitHubのWikiに変更があったら変更されたページの情報と変更内容付きで通知がくるようにする方法を紹介します。

方法

最初に方法を説明します。仕組みはその後に説明します。

clear-code/git-utils*1というフリーソフトウェアを使うと、GitHubのWikiが更新されたらページのURLと差分(diff)が入ったメールを通知することができます。

git-utilsのインストール方法はREADMEを参考にしてください。ここでは、git-utilsはhttp://git-utils.example.com/にインストール済みという前提で説明します。

Wikiの変更を通知したいプロジェクトのWebhooksにgit-utilsを指定します。Webhooksを追加する設定画面のURLは「https://github.com/#{user}/#{project}/settings/hooks/new」です。例えば、git-utilsプロジェクトのWebhooksを設定するURLは「https://github.com/clear-code/git-utils/settings/hooks/new」です。

この設定画面には「Payload URL」を設定するテキストボックスがあるので、そこに「http://git-utils.example.com/post-receiver/」と指定します。

その後、「Which events would you like to trigger this webhook?」と説明がある選択肢の中から「Send me everything.」を選びます。デフォルトは「Just the push event.」となっているので変更しないといけません。

これで設定は完了です。GitHubのWikiを更新すると指定したメールアドレスにdiff入りで通知メールが届きます。

なお、diffではなく、変更後のページの内容そのものの方がよい場合はAtomを購読します。AtomのURLは「https://github.com/#{user}/#{project}/wiki.atom」です。

仕組み

GitHubのWebhooksを使うとイベントが発生するごとにHTTPで通知を受け取ることができます。Wikiが変更されたときはgollumというイベントが発生します。git-utilsではこのイベントを契機に通知メールを作成します。

GitHubからの通知にはページ情報とコミットIDが含まれています。GitHubのWikiはGitで管理されているのでコミットIDとはGitのコミットIDそのものです。

WikiのGitリポジトリーは「https://github.com/#{user}/#{project}.wiki.git」になります。GitHubからの通知にはプロジェクトの情報も含まれているので、それらの情報からこのURLを作ることができます。

GitHubからの通知でGitリポジトリーとコミットIDを取得できるので、あとは通常のコミットメールの配送処理をするだけです。git-utilsにはコミットメールを配送するプログラムを含んでいるので、それを利用しています。

まとめ

GitHubのWikiが更新されたらdiff入りで変更内容を通知する方法を紹介しました。

diff入りで通知することで最新の情報を共有しやすくなります。複数人で情報共有のためにGitHubのWikiを使っている場合は使用を検討してみてください。今回の記事では省略したgit-utilsのインストールが大変という方は、相談してください。クリアコードでもgit-utilsをインストールしたサーバーを持っているのでそれを使えるようにすることができます。例えば、tdiary/tdiaryはクリアコードがインストールしたgit-utilsを使っています。

なお、Wikiの内容だけではなく、コミットの内容も共有することもオススメです。他の人が書いたコードから学べることはたくさんありますよ。(参考:コードリーダー育成支援

おまけ:RedmineのWikiが変更されたら差分付きで通知する方法

Feature #11530: Support hooks in mailer - Redmineのパッチとredmine-plugin-wiki-change-notifierプラグインを使うとRedmineのWikiが変更されたら差分付きで通知メールを届けることができます。インストール方法は次の通りです。

% wget http://www.redmine.org/releases/redmine-2.4.5.tar.gz
% tar xvf redmine-2.4.5.tar.gz
% cd redmine-2.4.5
% curl http://www.redmine.org/attachments/download/8244/support-hooks-in-mailer-for-r10463.patch | patch -p0
% git clone https://github.com/kou/redmine-plugin-wiki-change-notifier plugins/wiki_change_notifier
(以降は通常のインストール方法)

*1 git-utilsという名前は実体と乖離しているので、git-commit-emailとかという名前にした方がよいプロジェクトです。

2014-04-09

2014/6/22(日)に学生向けリーダブルコード勉強会を開催予定

要約:6/22(日)に学生向けリーダブルコード勉強会を開催する予定なので、興味のある学生の人は予定を空けておいてください。興味のありそうな学生を知っている人は教えてあげてください。

SEプラスさんがプログラミング好きな学生のためのリーダブルコード勉強会を企画しています。その勉強会の講演者・トレーナーをリーダブルコードの解説を書いた須藤が務めます。

リーダブルコードは内容が評価されていて、さらに、実際に広く読まれている本です。例えば、ITエンジニアに読んでほしい!技術書・ビジネス書 大賞 2014の技術書部門大賞を受賞したり、ジュンク堂書店池袋本店のコンピュータ書売上冊数ランキングで2012年2013年で2年連続1位になっています。学生のうちからこの本に書かれていることを理解し、実践していると、今後、プログラミングをする上で大きな力になるでしょう。

内容

SEプラスさんのページではまだ内容について触れていません。もうしばらくしたら公開されるでしょうが、ここでは一足早く少しだけ紹介します。

内容はリーダブルコードの解説に書いていることの体験です。解説では、本文に書いているリーダブルコードを書くための方法をどうやって実践するか、その方法を説明しています。つまり、この勉強会では学生がリーダブルコードに書いていることを単なる知識ではなく、実際に自分の技術や考え方として身に付けるきっかけとなる内容を目指します。

リーダブルコードを書くには読む人の視点を持っていることが重要です。リーダブルかどうかは読む人の視点での基準だからです。読む人の視点を持たずに書いているうちは、単に「想像して」リーダブルだろうコードを書いているだけです。読む人の視点を持っていれば、「事実に裏付けされた」リーダブルコードを書けます。

しかし、学生で読む人の視点を持っている人は少ないです。仕事では複数の人が同じソフトウェアを開発することが多く、また、リリースしたあとに継続して開発を続けることも多いので、コードを読む機会が増え、読む人の視点が身につきやすいです。一方、学生は自分ひとりで開発し、作って動かして研究成果が得られたらコードに触れることはない、というケースがほとんどです。そうすると、自分が書いたにしろ他の人が書いたにしろ、コードを読む機会がほとんどなく、読む人の視点を身につけることができません。

今回の勉強会ではこの「読む人の視点」を体験を重視します。具体的には次の流れで勉強会を進めることで、「読む人の視点」を体験します。

  1. 参加者全員にこの勉強会で開発するプログラムの仕様を伝える。
    • 参加者全員が同じプログラムを開発する。
    • プログラムは段階的に改良していくもので、どの時点でも動作する*1
    • プログラムの難易度は簡単なものにする*2
  2. 参加者全員が一定時間で各自プログラムを開発する。
    • 一定時間経過後、みんな途中まで開発を進めている状態にする。
  3. 参加者同士で開発しているプログラムを交換し、交換したプログラムを元に開発を継続する。
    • 開発を継続するためには交換したプログラム(= 他の人が書いたコード)を理解する必要がある。
      • 複数人での共同開発や作って終わりではない開発の疑似体験となり、コードを読む機会となる。これで「読む人の視点」を体験する。
      • 自分が書いたコードよりもリーダブルに書いているコードを見つけることを重視してもらう。ダメなところ探しに終始してグチグチ言っていたら終わっていたとなったら失敗。
  4. 実際に開発をし、「読む人の視点」を体験してみて感じたことをまとめ、整理する
    • 「面白かった」、「難しかった」だけで終わらせず、「なぜ難しかったか」など理由まで落としこむ。理由まで落としこめれば今回だけの体験で終わらず、自分に身についた今後も活かせる財産になるはず。

「コードを読む」というと「コードレビュー」というイメージが根強いので、どうしても「悪いところはないか?」という視点で読んでしまいがちです。そうではなく、「コードから学ぶ」という視点で読めるようになると、コードの理解も速くなりますし、読んでいる人の成長スピードもあがります。日々新しい技術が生まれ、学ぶことが増えている昨今、コードから学べるようになると重宝されることでしょう。

参加する学生の人には「読む人の視点」、もっと言うと「悪いところはないか?」ではなく「コードから学ぶ」という「読む人の視点」を身につけ、コードを読み、よい書き方を身につけ、それを自分が書くコードにも活かす、という習慣を体験してもらいたいです。

まとめ

6/22(日)に開催する学生向けリーダブルコード勉強会を紹介しました。リーダブルなコードを書くには読む人の視点をもつこと、ということを体験できる勉強会です。興味のある学生の人は予定を空けておいてください。興味のありそうな学生を知っている人は教えてあげてください。

学生ではないけど参加したい、新人研修や自分の開発チームでもやってみたいという人は相談してください。

この内容とは関係なく、リーダブルコードの社内勉強会をやっているからゲストで来て欲しいという場合は須藤 <kou@clear-code.com>に連絡してください。タイミングがあえばおじゃまします。

*1 例えば、電卓プログラムを作るということにしたら、最初は足し算しかできないが、次は掛け算ができるようになる、という感じ。最初の段階では足し算しかできないかもしれないが、動くことは動く。

*2 難しいプログラムを開発するためのテクニックを学ぶことが目的ではない。

2014-04-16

Jekyllで複数言語のコンテンツを継続してメンテナンスする方法

GitHub PagesのWebサイトジェネレーターであるJekyllで複数言語のコンテンツを管理する方法を紹介します。複数言語のコンテンツを管理するとは、例えば、英語と日本語のコンテンツを提供しているWebサイトにコンテンツを追加・修正・削除し、継続的にメンテナンスするということです。

最初に結論を書くと、jekyll-task-i18nを使えばGitHub Pagesの仕組みから逸脱せずに複数言語のコンテンツを継続的にメンテナンスできる仕組みができます。

複数言語のコンテンツを管理するときの問題

複数言語のコンテンツを管理するときに問題になることは、情報のズレです。一方の言語では提供されている情報が、他の言語では提供されていないという状態です。情報は提供されているが、古い情報のままということもあります。

「作った後は変更しない」というWebサイトではあまり問題になりませんが、作った後も継続して変更する場合は問題になります。継続して変更する場合はいかにコストを小さく複数言語のコンテンツを更新するかを考えなければいけません。コストが大きいと更新することが億劫になり、問題がより大きくなります。

複数言語のコンテンツを管理する方法

複数言語のコンテンツを管理する方法はいくつかあるので、それらをメリット・デメリット付きで紹介します。ここで紹介する方法は次の通りです。

  • 翻訳元コンテンツをコピーして翻訳
  • 翻訳箇所をマークアップし、コンテンツを処理する時に翻訳済みメッセージに置換
  • 翻訳元コンテンツから翻訳箇所を抽出し、翻訳済みメッセージと組みあわせて翻訳済みコンテンツを生成
コピーして翻訳

一番簡単で特に用意もいらない方法が翻訳コンテンツをコピーして翻訳する方法です。

どのような方法か例を使って説明します。

まず、en/index.mdという英語のコンテンツがあるとします。

en/index.md:

---
layout: en
title: Top page
---
# Hello!

これを翻訳し、ja/index.mdという日本語のコンテンツを作成することを考えます。

この方法では、次のように翻訳元のen/index.mdをコピーして、コピーしたファイルを編集し、翻訳します。

% mkdir -p ja
% cp en/index.md ja/
% editor ja/index.md
(↑で翻訳。)

ja/index.md:

---
layout: ja
title: トップページ
---
# こんにちは!

この方法のメリットは次の通りです。

  • 単純なのでわかりやすい。
  • 特にツールは必要ないのですぐに始められる。
  • Jekyllのプラグインも必要ないのでGitHub Pagesでも使える。

デメリットは次の通りです。

  • 翻訳元が変更された場合、変更点を見つけて追従することが大変。

この方法は、コンテンツの追加だけでコンテンツを追加するときは新規ファイルとして追加する、という運用であれば問題がありません。例えば、ブログのようなコンテンツです。

しかし、既存ファイルにコンテンツを追加したり、コンテンツの変更・削除がある場合はメンテナンスコストが大きくなります。このような場合は別の方法を検討したほうがよいでしょう。

Rabbitのサイト*1や、おそらくwww.ruby-lang.org*2もこの方法を使っています。

翻訳箇所をマークアップする方法

次は、翻訳箇所をマークアップし、コンテンツを処理する時に翻訳済みメッセージに置換する方法です。jekyll-localizationjekyll-i18n*3jekyll-multiple-languages-pluginが使っている方法です。独立したプラグインにはなっていませんが、bitcoin.orgもこの方法です。

これも例を使って説明します。最近もコミットがあるjekyll-multiple-languages-pluginを使います*4

まず、index.mdという英語のコンテンツがあるとします。

---
layout: en
title: Top page
---
# Hello!

これを翻訳し、ja/index.htmlという日本語のコンテンツを作成することを考えます。

まず、英語のコンテンツの翻訳対象のメッセージを{% t 翻訳メッセージのキー %}に置換します。今回の場合は「Hello!」を{% t top_page.title %}に置換します。

---
layout: en
title: Top page
---
# {% t top_page.title %}

英語のメッセージは_i18n/en.ymlに書きます。

top_page:
  title: Hello!

同様に、日本語のメッセージは_i18n/ja.ymlに書きます。

top_page:
  title: こんにちは!

_config.ymlに翻訳対象の言語を指定します。今回は英語と日本語なのでこうなります。

languages: ["en", "ja"]

HTMLを生成します。

% jekyll build

これで、_site/en/index.htmlに英語のコンテンツが生成され、_site/ja/index.htmlに日本語のコンテンツが生成されます。

_site/en/index.html:

...
<h1>Hello!</h1>
...

_site/ja/index.html:

...
<h1>こんにちは!</h1>
...

この方法ではRailsのi18n機能のように、元のコンテンツにはキーだけを記述し、YAMLに翻訳済みのメッセージを書きます。キーではなく翻訳対象のメッセージを使う方法や、YAML以外のファイルにメッセージを書く方法があってもよいはずですが、みんなこの方法を使っています。Railsの影響でしょう。

この方法のメリットは次の通りです。

  • 翻訳するメッセージだけに集中できる。「見出し」などの構造は気にしなくてもよい。
  • Railsのi18n機能を使っている人にはなじみがある。

デメリットは次の通りです。

  • キーだけ見てもどんなメッセージにすればよいかわかりにくいので翻訳が難しい。
  • オリジナルのメッセージ(今回の場合は英語のメッセージ)が変更されたことに気づくための仕組みがないので、翻訳済みのメッセージ(今回の場合は日本語のメッセージ)を追従することが難しい。
    • 例えば英語で「Hello!」を「Hello! This is a cool site!」に変更したときに気づく仕組みがないので、日本語は「こんにちは!」のままになってしまう。
  • Jekyllのプラグインとして動作するのでGitHub Pagesでは使えない。

Railsと同じような感覚で使いたい場合はこの方法がよいでしょう。

ただし、そのままではGitHub Pagesでは使えないので、GitHub Pagesで使いたい場合はローカルでHTMLを生成し、生成したHTMLをGitHub Pagesで使うようにする必要があります。

翻訳元コンテンツと翻訳済みメッセージから翻訳済みコンテンツを生成

最後の方法は最初の方法と2番目の方法を組み合わせたような方法で、2つの方法のよいところをとった方法です。

最初の方法では普通に書いたコンテンツそのものが翻訳対象でした。この方法でも普通に書いたコンテンツそのものが翻訳対象です。2番目の方法のように翻訳対象をマークアップしません。

翻訳済みコンテンツの作り方は2番目の方法と似ています。翻訳済みメッセージを準備することは2番目の方法と同じです。翻訳元コンテンツと翻訳済みメッセージを組みあわせて翻訳済みコンテンツを生成することも同じです。ただし、翻訳済みメッセージの管理方法が違います。

この方法を使っているのがjekyll-task-i18nです。

どのような方法か例を使って説明します。

まず、index.mdという英語のコンテンツがあるとします。

---
layout: en
title: Top page
---

# Hello!

これを翻訳し、ja/index.mdという日本語のコンテンツを作成することを考えます。2番目の方法のときはインストール方法を省略しましたが、この方法では省略すると何をしているかがわからないのでインストール方法も説明します。

まず、次の内容のGemfileとRakefileを作成します。

Gemfile:

1
2
3
4
source "https://rubygems.org/"

gem "jekyll-task-i18n"
gem "rake"

Rakefile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
require "bundler/setup"
require "jekyll/task/i18n"

Jekyll::Task::I18n.define do |task|
  task.locales = ["ja"]
  task.translator_name = "Kouhei Sutou"
  task.translator_email = "kou@clear-code.com"
  task.files = Rake::FileList["**/*.md"]
  task.files -= Rake::FileList["_*/**/*.md"]
  task.locales.each do |locale|
    task.files -= Rake::FileList["#{locale}/**/*.md"]
  end
end

task :default => "jekyll:i18n:translate"

初期化します。

% bundle install

ここからが実際の翻訳作業です。

まず、翻訳対象のメッセージを抽出します。

% bundle exec rake

これで次の内容の_po/ja/index.edit.poができます。

_po/ja/index.edit.po:

# 省略
msgid ""
msgstr ""
"省略"

#: ../../index.md:1
msgid ""
"---\n"
"layout: en\n"
"title: Top page\n"
"---"
msgstr ""

#: ../../index.md:6
msgid "# Hello!"
msgstr ""

この中のmsgid "..."となっている部分が翻訳対象のメッセージです。index.mdから自動抽出されたものです。抽出方法は単に2つ以上の連続する空行で区切っているだけです。Markdownをパースしていたりはしません。

msgid "..."の部分を翻訳し、msgstr ""に入れます。

_po/ja/index.edit.po:

# 省略
msgid ""
msgstr ""
"省略"

#: ../../index.md:1
msgid ""
"---\n"
"layout: en\n"
"title: Top page\n"
"---"
msgstr ""
"---\n"
"layout: ja\n"
"title: トップページ\n"
"---"

#: ../../index.md:6
msgid "# Hello!"
msgstr "# こんにちは!"

これで翻訳済みメッセージができました。翻訳元コンテンツと翻訳済みメッセージを使って翻訳済みコンテンツを生成します。

% bundle exec rake

これでja/index.mdに翻訳済みコンテンツができます。

ja/index.md:

---
layout: ja
title: トップページ
---

# こんにちは!

できあがるものはコピーして翻訳する方法と同じものです。Jekyllが処理済みのHTMLを生成するのではなく、Jekyllの入力ファイルを生成するので、ja/index.mdをpushすればGitHub Pagesでそのまま使えます。

この方法のメリットは次の通りです。

  • JekyllのプラグインではないのでGitHub Pagesでも使える。
  • 翻訳対象のメッセージがすぐ近くにあり、確認しながら翻訳できるので翻訳しやすい。
  • 翻訳対象のメッセージが変更されたらツールが検出してくれるので、追従しやすい。

デメリットは次の通りです。

  • gettextという仕組みになじみがない人*5は最初の敷居が高い。
  • Jekyllだけでなく、RakeやBundlerも使うのでRubyになじみのない人は最初の敷居が高い。

jekyll-task-i18nを使ったサンプルがjekyll-task-i18n/sampleにあるので、それを使えば手元で試すことができます。

翻訳対象のメッセージの追加・削除に対するツールの支援があるのはこの方法だけなので、コンテンツの追加だけではない複数言語対応のWebサイトを継続してメンテナンスするならこの方法が適切です。

JekyllのプラグインではないためGitHub Pagesの仕組みから逸脱しません。そのため、2番目の方法と違い、GitHub Pagesでも使えます。

ただし、それほど頻繁に更新しないWebサイトには大げさです。その場合はコピーして翻訳する方法でも十分でしょう。

droonga.orgはこの方法を使っています。droonga.orgにはリファレンスマニュアルやチュートリアルがあり、コンテンツの追加だけでなく、変更・削除が多いからです。

まとめ

Jekyllを使っているWebサイトで複数言語のコンテンツを管理する方法について説明しました。説明した方法は次の3つです。

  • 翻訳元コンテンツをコピーして翻訳
  • 翻訳箇所をマークアップし、コンテンツを処理する時に翻訳済みメッセージに置換
  • 翻訳元コンテンツから翻訳箇所を抽出し、翻訳済みメッセージと組みあわせて翻訳済みコンテンツを生成

コンテンツを追加するだけだったり、それほど変更がない場合は最初の「翻訳元コンテンツをコピーして翻訳」方法で十分でしょう。

コンテンツの変更・削除がそれなりにあるようなら最後の方法がよいでしょう。

最後の方法に興味がある人はgettextとバージョン管理システムの相性の悪さを解消する案も参照してください。jekyll-task-i18nはこの案を実装しています。

*1 GitHub Pagesは使っていませんがJekyllは使っています。

*2 www.ruby-lang.orgもGitHub Pagesを使っていません。

*3 開発は終了しています。

*4 本質的なことではないのでjekyll-multiple-languages-pluginのインストール方法は省略して、翻訳する流れだけ説明しています。そのため、この通りやっても手順が足りず試すことはできません。

*5 例えば、Railsのi18n機能しか知らない人。

2014-04-23

LXCのテンプレートをカスタマイズする方法

最近LXC - Linux Containersで開発環境を構築したので、その作業の中からコンテナのカスタマイズについて書きます*1

LXCではlxc-createコマンドでテンプレートを指定してコンテナを作成します。例えば、Fedora19のコンテナを作成するコマンドは以下の通りです。

$ sudo lxc-create -t fedora -n fedora19 -- --release 19

これで作成されるのはミニマムな環境なので、色々とパッケージを追加したりユーザを追加したり設定をしたりして使うことになります。 Chef などのプロビジョニングツールを利用して初期設定をすることもできますが、開発環境にそれらのツールを導入したくない場合もあります。

ここではFedora向けのテンプレートを改造して、パッケージを追加する方法を簡単に紹介します。

まず、実装を確認します。/usr/share/lxc/templates/lxc-fedoraの内容を確認すると、ただのシェルスクリプトであることがわかります。

このファイルの最後の方を確認すると以下のように、前の方で定義した関数を順番に実行しているだけです。全部引用すると長くなるので重要な部分のみを引用しています。

1
2
3
4
5
6
7
8
9
10
11
trap revert SIGHUP SIGINT SIGTERM
copy_configuration
install_fedora
configure_fedora
type /bin/systemd >/dev/null 2>&1
if [ $? -ne 0 ]; then
    configure_fedora_init
else
    configure_fedora_systemd
fi
echo "container rootfs and config created" 

これを見るとcopy_configurationで設定をコピーしてinstall_fedoraでFedoraをインストールした後configure_fedoraでFedoraの設定をしています。 最後にsystemdの有無で、設定を変えています。

順番に見ていくとcopy_configurationはコンテナの設定ファイルを所定のパスに作成しているだけなので、今回は変更する必要がありません。

install_fedoraの中では、キャッシュがあったらそれを更新(update_fedora)してから、コピー(copy_fedora)しています。 キャッシュがなればダウンロード(download_fedora)してから、コピー(copy_fedora)しています。

なので、download_fedoraの中身を見れば、どうやってカスタマイズすれば良いのかわかりそうです。

download_fedoraではyumの--installrootオプションを使ってパッケージのインストール先を変更しつつchroot環境を構築し、完成したディレクトリツリーを所定のパスに移動しています。 またFedoraのバージョンでfedora-releaseというパッケージの命名規則が変わっていますが、うまくインストールできるようにしています。

重要な部分を引用すると以下の通りです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
download_fedora()
{
    # download a mini fedora into a cache
    echo "Downloading fedora minimal ..." 
    YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck" 
    PKG_LIST="yum initscripts passwd rsyslog vim-minimal dhclient chkconfig rootfiles policycoreutils fedora-release" 
    MIRRORLIST_URL="http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-$release&arch=$arch" 

    # fedora-release-*.rpm をダウンロードしている部分は省略

    mkdir -p $INSTALL_ROOT/var/lib/rpm
    rpm --root $INSTALL_ROOT  --initdb
    rpm --root $INSTALL_ROOT -ivh $INSTALL_ROOT/fedora-release-$release.noarch.rpm
    $YUM install $PKG_LIST

    mv "$INSTALL_ROOT" "$cache/rootfs" 
    echo "Download complete." 

    return 0
}

単純に考えるとPKG_LISTに欲しいパッケージを追加すればよさそうです。しかし、それだとパッケージリストを変更して試すために毎回テンプレートを修正しなければなりません。 それは面倒なので、追加のパッケージリストは別ファイルにしてテンプレートのオプションで指定できるようにしてみます。

元にしたテンプレートをコピーして/usr/share/lxc/templates/以下に lxc-で始まる名前で置けばテンプレートとして使うことができます。 例えばlxc-fedora-customという名前でファイルを作成するとlxc-createで指定するテンプレート名はfedora-customになります。

ここではFedora向けのテンプレートをコピーしたものに機能を追加します。

差分はこうなります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
--- lxc-fedora  2014-04-28 11:38:41.960333132 +0900
+++ lxc-fedora-custom      2014-04-28 12:18:29.650862732 +0900
@@ -178,6 +178,12 @@
         return 1
     fi

+    if [ ! -z "$package_list" ]; then
+        echo "Install extra packages" 
+        $YUM groupinstall $(grep -E "^@" "$package_list" | sed -e "s,^@,,")
+        $YUM install $(grep -v -E "^(#|@)" "$package_list")
+    fi
+
     mv "$INSTALL_ROOT" "$cache/rootfs" 
     echo "Download complete." 

@@ -322,12 +328,13 @@
   -c,--clean        clean the cache
   -R,--release      Fedora release for the new container. if the host is Fedora, then it will defaultto the host's release.
   -A,--arch         NOT USED YET. Define what arch the container will be [i686,x86_64]
+  --package-list    Path to package list file
   -h,--help         print this help
 EOF
     return 0
 }

-options=$(getopt -o hp:n:cR: -l help,path:,name:,clean,release: -- "$@")
+options=$(getopt -o hp:n:cR: -l help,path:,name:,clean,release:,package-list: -- "$@")
 if [ $? -ne 0 ]; then
     usage $(basename $0)
     exit 1
@@ -342,6 +349,7 @@
         -n|--name)      name=$2; shift 2;;
         -c|--clean)     clean=$2; shift 2;;
         -R|--release)   release=$2; shift 2;;
+        --package-list) package_list=$2; shift 2;;
         --)             shift 1; break ;;
         *)              break ;;
     esac

1行に1つパッケージ名を書いたテキストファイルを用意して --package-list オプションに指定すれば追加のパッケージをインストールしたコンテナを簡単に作ることができます。

このパッチをあてたテンプレートは以下のように利用します。

$ sudo lxc-create -t fedora-custom -n my-fedora19 -- --release 19 --package-list packages.txt

追加のパッケージをインストールする以外にも様々なカスタマイズが考えられます。

  • Ubuntuのテンプレートのようにホスト側のユーザをコンテナ側にも作成して、そのユーザのホームディレクトリをバインドマウントする
  • アーキテクチャを指定できるようにする
  • mirror URLを指定できるようにする
  • 別のディストリビューションのテンプレートを作成する

まとめ

LXCのテンプレートをカスタマイズして、初期導入パッケージをカスタマイズする方法を紹介しました。

*1 LXCのバージョンは0.9系を想定していますが、0.8でも1.0でも基本的には変わりません。

2014-04-30

«前月 最新記事 翌月»
タグ:
年・日ごとに見る
2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|