Mercurialのインストールからsshとhttp(cgi)でリポジトリを読み書きできるようにするまで

debian etchのサーバにMercurialの最新版(1.1.2)をインストールし、リポジトリを公開した際の作業手順です。

思い通りになるまでが想像より面倒くさかったので、メモをまとめてみました。debian lennyやubuntuでも基本的な手順は変わらないと思います。

リポジトリsshとhttp(cgi)の双方から読み書きできるように設定します。Apacheリポジトリの所有者と異なるwww-data:www-dataで動作している状態を想定しています。本当はmod_userdirやsuEXECを使えば簡単なのかも知れません。

参考にしたウェブサイトは最後の参考リンクとしてまとめました。詳しくはリンク先や公式ドキュメントを参照して下さい。

ダウンロードと展開

debianリポジトリにあるのは古いので最新版をダウンロードした方が良いです。適当にtarボールを展開します。

wget http://www.selenic.com/mercurial/release/mercurial-1.1.2.tar.gz
tar zxvf mercurial-1.1.2.tar.gz

ビルドとインストール

MakefileはPREFIX=/usr/localとなっていたので、そのままmake installしてしまいます。必要であればPREFIXなどを自分の好きなように設定しましょう。

cd mercurial-1.1.2
make install

ビルドには恐らく以下のパッケージを入れておけば大丈夫だと思います。

apt-get install build-essential python-dev

/usr/local/binにパスが通っていればhgコマンドでバージョンが確認できます。

hg --version

リポジトリの作成と共有設定

ユーザ作成

Webとssh両方から叩くためにユーザとグループ(ここではhg:hg)を作成してしまいます。実際にはグループだけでも良いですが、わかりやすくユーザとグループを作ります。本来はここで公開鍵の設定をした方が良いと思いますが、割愛します。

useradd -m hg
passwd hg
リポジトリ作成

hgユーザになって適当なディレクトリ(/home/hg/repos)でリポジトリを作ります。

mkdir repos
cd repos
hg init

リポジトリの設定ファイルhgrc(/home/hg/repos/.hg/hgrc)でWebアクセスの許可を設定します。

[web]
push_ssl = false
allow_push = *
パーミッション設定

www-dataとの共有のためファイルとディレクトリにグループでの書き込み権限を与えます。また.hg、.hg/store、.hg/store/dataにはsetgidビットを付けてグループが引き継がれるようにします。

chmod g+w .hg .hg/* .hg/store/*
chmod g+s .hg .hg/store .hg/store/data

グループ設定

リポジトリに書き込み権限を与えるため、Apacheの実行ユーザwww-dataをhgグループに参加させておきます。

gpasswd -a www-data hg

Apacheの設定

CGIの設定

hgweb.cgi設置先のディレクトリ(ここでは/var/www/hg)でCGIを実行できるように設定します。AllowOverrideが使えるなら.htaccessで設定しても良いです。ScriptAliasの方が筋なような気もしますが、ここでは扱いません。アクセス制限をするなら、ここで必要に応じてBasic認証をかけます。

<Directory /var/www/hg>
    Options +ExecCGI
    AddHandler cgi-script .cgi
    Order allow,deny
    Allow from all
</Directory>
hgrcの作成

ApacheのためのMercurial設定を記述するhgrcファイルを作っておきます。とはいえApacheにはホームディレクトリはないのが一般的だと思います。

ここでは/etc/apache2/hgrcというファイルとして置くことにします。所有者はwww-data:www-dataでパーミッションは444あたりが無難です。

hgrcではhg:hgを信頼するよう設定します。

[trusted]
users = hg
groups = hg

後述するhgweb.cgiでこのhgrcを使うよう設定をしないと、ユーザと所有者の異なるhgrcは信頼できないというエラーが発生して動作しません(以下)。

Not trusting file /home/hg/repos/.hg/hgrc from untrusted user hg, group hg

hgweb.cgiの設置

hgweb.cgiのコピー

hgweb.cgiMercurialのtarボールを展開した中に入っています。Apacheのhtdocs以下の適当な場所にhgweb.cgiをコピーします。名前はindex.cgiとするとDirectoryIndexになって都合が良いかも知れません。

cp hgweb.cgi /var/www/hg/index.cgi
hgweb.cgiの修正

hgweb.cgiは以下のように変更しました。

  • import sysのコメントアウトを外して、次の行でmercurialがインストールされたパスを設定します。
    • 環境やインストールの方法によってパスは異なります、インストール先をきちんと確認しましょう。
  • import osのコメントアウトを外して、次の行は必要に応じてUTF-8を使うよう設定します。
  • HGRCPATHにApacheのために用意したhgrcファイルのパスを指定するよう行を追加します。
  • 最後の方の行でhgwebで扱うリポジトリと名前を指定します。
#!/usr/bin/env python
#
# An example CGI script to use hgweb, edit as necessary

# adjust python path if not a system-wide install:
import sys
sys.path.insert(0, "/usr/local/lib/python2.4/site-packages/")

# enable importing on demand to reduce startup time
from mercurial import demandimport; demandimport.enable()

# Uncomment to send python tracebacks to the browser if an error occurs:
#import cgitb
#cgitb.enable()

# If you'd like to serve pages with UTF-8 instead of your default
# locale charset, you can do so by uncommenting the following lines.
# Note that this will cause your .hgrc files to be interpreted in
# UTF-8 and all your repo files to be displayed using UTF-8.
#
import os
os.environ["HGENCODING"] = "UTF-8"
os.environ["HGRCPATH"] = "/etc/apache2/hgrc"

from mercurial.hgweb.hgweb_mod import hgweb
import mercurial.hgweb.wsgicgi as wsgicgi

application = hgweb("/home/hg/repos", "test repos")
wsgicgi.launch(application)


オリジナルのhgweb.cgiとの差分は以下です。

6,7c6,7
< #import sys
< #sys.path.insert(0, "/path/to/python/lib")
---
> import sys
> sys.path.insert(0, "/usr/local/lib/python2.4/site-packages/")
21,22c21,23
< #import os
< #os.environ["HGENCODING"] = "UTF-8"
---
> import os
> os.environ["HGENCODING"] = "UTF-8"
> os.environ["HGRCPATH"] = "/etc/apache2/hgrc"
27c28
< application = hgweb("/path/to/repo", "repository name")
---
> application = hgweb("/home/hg/repos", "test repos")

おわり

以上で設定は完了です。それぞれ以下のURLを指定して、リポジトリにアクセスできます。

僕の環境ではssh/httpでのclone/pushと、別の方でcommitしたファイルの変更とpushまで、きちんと動作しています。

公式のwikiにあるようにumaskを002に設定する必要があると思ったのですが、設定しなくてもファイルシステム上ではumask 002のように振る舞っていて、特に問題が出ていません。若干気にかかるところです。

debianでiproute2を使ったルーティングを設定する

iproute2を使ったルーティング設定をしたい場合、RedHat系だと/etc/sysconfig/network-scripts以下のファイルを編集して設定できますが、Debian系はどうすれば良いのか調べてみたら次のページが見つかりました。

Routing for multiple uplinks

このページでは/etc/network/interfaces中でpost-up/post-downを使って、ifup/ifdown時にiproute2コマンドを実行して設定しています。

紹介されている設定例は、Linux Advanced Routing & Traffic Control HOWTOの「4.2. 複数のアップリンク/プロバイダに対するルーティング」と同一です。

http://www.linux.or.jp/JF/JFdocs/Adv-Routing-HOWTO/lartc.rpdb.multiple-links.html

僕はバランシングの必要がなかったので、再起動でソースアドレスルーティングが設定される部分までしか確認していません。詳しくはリンク先を参照して下さい。

以下はリンク先を参考に、手元の環境でソースアドレスルーティングを設定した作業メモです(※繰り返しますがバランシングはしていません)。

インストール

apt-get install iproute

セットアップ

eth0が192.168.1.2/24でゲートウェイが192.168.1.1、eth1が192.168.2.2/24でゲートウェイが192.168.2.1とします。デフォルトゲートウェイは192.168.1.1にします。どちらもアップリンクでLANはありません。

アップリンクのためのテーブルT1/T2を作ります。/etc/iproute2/rt_tablesを以下のように記述。

#
# reserved values
#
255     local
254     main
253     default
0       unspec
#
# local
#
200     T1
201     T2

続いて/etc/network/interfacesを以下のように記述。

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
        address 192.168.1.2
        netmask 255.255.255.0
        post-up ip route add 192.168.1.0/24 dev eth0 src 192.168.1.2 table T1
        post-up ip route add default via 192.168.1.1 table T1
        post-up ip route add default via 192.168.1.1
        post-up ip rule add from 192.168.1.2 table T1
        post-down ip rule del from 192.168.1.2 table T1

auto eth1
iface eth1 inet static
        address 192.168.2.2
        netmask 255.255.255.0
        post-up ip route add 192.168.2.0/24 dev eth1 src 192.168.2.2 table T2
        post-up ip route add default via 192.168.2.1 table T2
        post-up ip rule add from 192.168.2.2 table T2
        post-down ip rule del from 192.168.2.2 table T2

この状態でifup/ifdownするとiproute2で経路が追加/削除される事が確認できます。

rubyscript2exeが例外can't modify frozen string (TypeError)で動作しない問題

debian lennyのruby 1.8.6の環境で、gemから取ってきたrubyscript2exe 0.5.3がcan't modify frozen string (TypeError)という例外を出して動作してくれませんでした。

ソースを見るとString#replaceでコケており、Rubyのバージョン(?)によって組み込み変数$0などがデフォルトでfrozenされているのが問題のようでした(etchの1.8.5だとこの例外は出なかった)。

例外が出た以下3箇所を場当たり的に書き直したら動作しました。String#replaceを使う必要は特になさそうだったので、単純に代入に置き換えました。またGem::Exceptionは無いと言われたので、単なるExceptionを継承するようにしました。

/var/lib/gems/1.8/gems/rubyscript2exe-0.5.3/bin/rubyscript2exe 5行あたり

-   $0.replace(realstuff)        if isapplication
+   $0 = realstuff        if isapplication

/var/lib/gems/1.8/gems/rubyscript2exe-0.5.3/realstuff.rb 621行あたり

-       $0.replace(File.expand_path("./init.rb"))
+       $0 = File.expand_path("./init.rb")

/usr/lib/ruby/1.8/rubygems/remote_fetcher.rb 19行あたり

-   class FetchError < Gem::Exception
+   class FetchError < Exception

正しいかは微妙なところですが、これでひとまずどうにかなっています。debianだけでなくRubyのバージョン依存だとしたら同じ所でひっかかる人も居るのではと思います。rubyscript2exeは07年5月からメンテナンスされていませんが、対策されないのでしょうか。

http://rubyforge.org/projects/rubyscript2exe/

PidginでHTTP Proxyを越えてGoogle Talkに接続する

Google Talkは良くできていてHTTP Proxy下でも簡単に動作してしまいますが、PidginだとSSLを使ってポート443で接続するよう設定が必要です。日本語の解説が見当たらなかったので書いておきます。


  • 「古いSSL(ポート番号5223)を強制的に使用する」にチェック
  • 「接続するポート番号」を「443」に変更
  • 「プロキシのオプション」は環境に応じてお好みで

「窓使いの憂鬱」Linux対応版でセミコロンをエンターに

るびま増井俊之さんがセミコロンをリターンにしているというのを読んで以来、Windowsでは「窓使いの憂鬱」(mayu)を使ってセミコロンをEnterに、Ctrl + Enterをセミコロンにバインドしていました。

Linuxを使い始めた時に同様のキーバインドを再現できないのか調べてみたのですが、xmodmapは複雑なモディファイアキーとの組み合わせを扱うことができず、http://sakanapenguin.net/blog/2007/08/19/post145/で紹介されているxbindkeysとxvkbdを使ってCtrl + セミコロンでEnterを送る方法は動作が重く、あきらめていました。

http://members.at.infoseek.co.jp/hattoushin_uma/

が、なんと昨年末から窓使いの憂鬱LinuxMacにポーティングされています。感激です!!配布ページによると、まだ動作しない機能も多いようですが、キー置き換えは既に大体使える状態になっているとのこと。

親切なREADMEがあるので詳細は割愛しますが、debian lennyでは説明通りライブラリを揃えてmake && make installするだけでインストールできました。セミコロンをEnterにあてる設定も、Windowsから設定ファイルを書き換えることもなく完全に動作しています。

#104キーボードでセミコロンをEnterにする設定例
include "104.mayu"
keymap Global

#CapsLockをCtrlに
mod control += CapsLock
key *CapsLock = *LControl

#セミコロンをEnterに、Ctrl + セミコロンをセミコロンに
key *IL-*IC-Semicolon = Enter
key C-Semicolon = Semicolon

それにしても、もともと窓使いにジョブチェンジしたUN*X Wizardの憂鬱を和らげるためのソフトがUN*Xに逆移植され、Windowsで使っていた設定ファイルはそのままに、今度は犬使いの憂鬱を解消することになるとは…なんとも変な話です。私家版が開発される一方で、本家はVista対応の困難さから開発が終了しているのもまた面白いところ。

Amazon S3をjgitでgitリポジトリとして活用する

ふとした興味からAmazon S3をgitリポジトリにできないかと調べてみたところ、ピュアJavaのgitの実装JGitを使えば可能だということがわかりました。普通はgithub.comとかで事足りると思いますが、「gitリポジトリを信頼できる場所にバックアップしておきたい!」というような場合に利用できるかも知れません。以下の作業で動作は確認していますが、JGit + Amazon S3が本格的に使い物になるのかは未検証です。

JGitのインストール

JGitのCLIをインストールします。JGitはEclipseプラグインのEGitに含まれているので、まずEGitのgitリポジトリからEGitを取ってきます。

git clone git://repo.or.cz/egit.git

egit直下にあるmake_jgit.shを実行してJGitのバイナリを作ります。

cd egit
./make_jgit.sh

動作確認でバージョンを表示させてみます(僕が試した時点のmasterはv0.4.0.129でした)。

./jgit version

jgitでAmazon S3をgitリポジトリとして使う

設定ファイルの作成

ホームディレクトリに適当な名前(.jgit_s3とか)で以下のようにAWSのアクセスキーとシークレットキーを書いたファイルを作ります。もしHTTPで公開しないならaclはpublicではなくprivateにします。

accesskey: AWSAccessKey
secretkey: AWSSecretKey
acl: public
Amazon S3へのpush

jgitの独自拡張でamazon-s3://をつけてAmazon S3にアクセスできます。次のコマンドはバケットYOURBACKETの/projects/foobar.git以下のオブジェクトとしてgitリポジトリをpushする例です。

jgit push amazon-s3://.jgit_s3@YOURBACKET/projects/foobar.git refs/heads/master
Amazon S3からのpull

設定ファイルでaclをpublicにしてpushしていればHTTPで公開されるので、普通にgitを使ってpullできます。

git pull http://YOURBACKET.s3.amazonaws.com/projects/foobar.git

jgitでAmazon S3を直接叩くこともできますが、jgit pullはできないのでfetch/mergeするしかないようです。

jgit fetch amazon-s3://.jgit_s3@YOURBACKET/projects/foobar.git
git merge s3/master

スーパーpre記法のヘルプを見ていたらwhitespaceに対応していることに気づいた

もちろんハイライトしても空白。

茶目っ気ありすぎだろう。

Say hello.