トップ «前の日(12-17) 最新 次の日(12-19)» 追記

2003-12-18

_ エディタの行間

ここ2ヶ月で急速にメインのエディタが xyzzy から Emacs に移行してきてるんだけど、最近になって気づいたことがある。

それは行間。

たまに xyzzy を使うと非常に画面が狭く感じられた。なんでかなと思ったら Emacs では(というか rxvt の設定なんだけど)行間を取っていなくて、xyzzy は 2, 3 ピクセルの行間を確保するようにしていたから。ところが xyzzy の行間を 0 にしておいたらメールを書くときなどに上がってきた xyzzy がすごく窮屈に感じる。

要するにコードを書くときと日本語を書くときに適した行間が違うってことなんだな。でも xyzzy では行間はモードごとに切り替えることはできない。システム共通の設定になっている。まぁ普通はそうだろう。でも、実はモードごとに行間変えられた方が便利なんだな、と感じた。Emacs は X でならできるかなぁ。-nw だと設定は terminal 依存だから無理だけど。

Tags: Tool

2004-12-18

_ いわゆる全文検索エンジン

  • estraier
    • 最近あちこちで名前を聞く
    • ports にはある。pkgsrc, Fink にはない。
  • Namazu
    • もう超有名だけどパッチワーク的
    • ports, pkgsrc にはある。Fink にはない。
  • FreyaSX
    • Namazu や estraier のようにあれこれ依存しないもの
    • 昔あった Freya をモダンな OS(OS X とか) に対応させつつ機能拡張をはかったもの
    • ports, pkgsrc, Fink にない(入ってるパッケージシステムってあんのかな?)
  • mnogosearch
    • 海外では有名
    • ports, Fink にはある。pkgsrc にはない。

easy packages を意図的に無視しているのは、えーと頑張ってる作者さんには申し訳ないんですが本家がやめたんだし、どうにも先細り感が拭えないので。Gentoo も入れてみたけど現時点では全然まだまだなんで候補には入ってません。

で、mnogosearch は Segmenters for Chinese, Thai and Japanese languages によると ChaSen か MeCab を要求するんだけど、どっちも Fink には入ってないんだな。どないせえと。

Tags: 日々 Tool

_ CSS デザイン二題

旧来のテクニックの延長にあるデザイン

Stylesheet Stylebook をつらつらと眺めていて、Apple のサイトでスペーサーを CSS で実現しているようなことが書いてあった。現物をまだ確認していないんだけど、確かにその方法は継承周りとか細かいバグを持ったブラウザでもデザインを再現できる方法としていいかも、と思った次第。

ほんとは構造ありきの Strict + CSS の方が好きだけど、そういう構成でも「遊び」がないとほんとにクールなデザイン(とっくに死語)にはならないので、その延長と考えればそんなに抵抗ないかな?

もともとシンプルなデザイン

続きで。米 Yahoo! はもっと大胆に table 組みをやめるらしい。実際には細かいところでちょこちょこ使っているんだけど、大枠は table じゃなくなってる。Yahoo! ならではのシンプルなデザインだから可能なのかもしれないなーと思ってみたり。あ、agent 判別して古いブラウザには table 組みを返すのね。さすがっちゅーかなんちゅーか。まー完全にテンプレートでページ作ってれば切り替えるのは雑作もないことですわな。

Tags: Web

_ 条件判別のスピード

条件式の省略化時の速度

元ネタはよく分からないんだけど、だらだら条件書くより上手に減らすと速いぞ、ってことなのかな?

リンク先のコメントにも書いたように個人的には正規表現厨の可読性命で Perl 使い*1なので preg_match() をよく使う。マニュアルにも ereg より速いと書いてあるし、今回も実際に速かった。

preg_match で絞るのはブラウザから渡ってくる値を手早くチェックしやすいからだ。ほんとは賢いフレームワークを使うとこういうのは楽できるのかもしれないけど、PHP で名の通ったフレームワークを知らないのでこの辺はいつもゴリゴリと書いている。

Tags: Web PHP

*1 いろいろなものが矛盾しているように見えるけど気にしてはいけない

_ DocBook 日本語訳

DocBook TDG 日本語翻訳版

すげー。GFDL に従う翻訳版。使う機会ないけど Web + 印刷前提で大量のドキュメントをまとめるのには使えそうなのでずいぶん前から注目はしてる。今は PukiWiki に自前 CSS でどうにかなってるんですが。

Tags: Tool

_ ふーん < ITSS

高度IT人材の育成 (経済産業省)

のいちばん下に「情報処理技術者試験 とITスキル標準との対応」というものがあるんですが、セキュリティって扱い軽いですねぇ。試験内容には経営的な側面も入ってるんですが、あんまり ITSS 的には扱いは重要じゃないように見えます。いいんかいな、それ。

まー結局システムを作って動かしてお金を回す、という意味ではセキュリティは貢献しませんからなぁ。リスクを減らすことでひょっとすると発生したかもしれないコストを抑えることはできますが、逆にそのためのランニングコストも発生します。なんとなく、ITSS を誰がほしがったのかが見え隠れしますな。

Tags: 日々 Biz Edu

2005-12-18

_ 天寿全う

自宅サーバに突っ込んでいた、いつのものかもよく分からない*1 CD-ROM ドライブがインストールの最後の最後の段階に死んだ。FreeBSD はインストール途中に kernel panic に陥り、ドライブはピンを突っ込んでもトレイが出てこない、見事ないきっぷり。*2

大往生ってやつですか。とりあえず予備の CD-RW に載せ換えられちゃう扱いなわけですけど、立派に働いたんじゃないかと。

Tags: 日々 Tool

*1 恐らく日立FLORA Pen133 かなんか。

*2 微妙に浮いていたので指力で引っ張って開けた。


2008-12-18

_ Capistrano は思ったよりシンプルで思ったよりすごい

システム管理者のみなさん、こんにちは。今日は Rails アプリの deploy ツールとして有名な(らしい)Capistrano についてです。紹介? いえいえ。紹介はすでに有名な人たちによってなされています。ワタシがしたいのは検討。こいつはどこにどのように使えそうか。

Capistrano: Home

システム管理の話なのになんで Puppet じゃないの?と思うかもしれません。それは、以前 Puppet の OSX 対応があまりよくなかったことと、また自分の環境が PPC Mac だったため、仮想マシンを使って他の OS を動かすのも現実的でなく、面倒になってしまっていたからです。

で、巡り巡って Capistrano って実は deploy 以外にも結構使えそうじゃない?と思えましたよというお話。想定しているバージョンは Capistrano 2.5.3 です。

なお、例によって嘘書いてる可能性があります。識者のツッコミお待ちしております。

Capistrano の動作に必要なのは Ruby と ssh だけ

  • Puppet は daemon をいくつか用意してやる必要があります。
    • https を使ってくれるので fw friendly ですが、それにしたっていろいろ準備が必要です。
  • Capistrano の準備で大事なのは以下の2点だけ。
    • Capistrano*1 をセットアップする1台のマシン
    • 管理される方のマシンには sshd と作業用の ssh アカウント

しかも Puppet と違い C/S 方式ではないため、Capistrano のセットアップが必要なマシンは1台だけです。

なんか、ちょっとお手軽な感じがしませんか。

Capistrano 自体は Windows でも動く

依存している gem パッケージは以下の通り。

$ gem dependency capistrano
Gem capistrano-2.5.3
  net-ssh (>= 2.0.0, runtime)
  net-sftp (>= 2.0.0, runtime)
  net-scp (>= 1.0.0, runtime)
  net-ssh-gateway (>= 1.0.0, runtime)
  highline (>= 0, runtime)
  echoe (>= 0, runtime)

あと echoe がこんな感じ。*2

$ gem dependency echoe
Gem echoe-3.0.2
  rake (>= 0, runtime)
  rubyforge (>= 1.0.0, runtime)
  highline (>= 0, runtime)

ext なライブラリはないので Capistrano 自体は Windows でも動かせます。*3自分で実際に確認はしてないですけど、動かしている例は探せばすぐ見つかります。

ただ管理対象は ssh でなんでもできる Un*x 系システムじゃないと Capistrano の利用に旨味はないでしょう。

要するにできることは ssh HOST COMMAND

ssh は interactive な login shell を提供するだけではなく、

ssh HOST COMMAND

の形で

HOST に接続して COMMAND に書かれた処理を実行して終了する

という使い方もできます。大雑把に言うと Capistrano はこの機能をより便利に使うために

  • 接続先の管理と接続の自動化
  • 接続先と作業内容のセットをタスクで管理
  • タスクの実行

を提供してくれるものです。そして

そのために Rake によく似た DSL を使う

ようになっています。

deploy ツールとして紹介されることの多い Capistrano ですが、それは deploy 用のタスクがあらかじめ定義されていて、変数をセットするだけで便利に使えるようにしてあるからであって、

タスクを用意すれば ssh でできる仕事はなんでもできますし、remote の仕事だけでなく local の仕事もできます。

たぶん。

ただし、Puppet と違い、接続先のサーバ OS の抽象化などは行ってくれないため、基本的にその部分は生で相手しないといけません。逆に Puppet のように独自文法の習得を要求しません。

ということは従来の方法からの移行コストが小さい

まともな管理者なら、サーバ上のたいていの作業は sh や Perl、Ruby などのスクリプトである程度自動化されていると思います。これが cron ジョブとして管理できるなら手作業はずいぶん減っているはずです。ただ、

完全に定期実行になっていない作業

も中にはあるでしょう。その場合、しぶしぶ個々のサーバにログインしてスクリプトを実行していませんか? 恥ずかしながら自分はそうです。しかし Capistrano を導入すれば

最後の「ログイン -> 実行」の部分を自動化、管理できます。

そうです。個々のサーバの管理方法を大幅に変える必要はありません。「ログイン -> 実行」という、最後に残った手作業部分を Capistrano のタスクとして管理できるようになるだけなのです。しかもサーバ側は基本的にいじる必要がありません。

これが複数のサーバ上の作業なら目に見えて楽になりますし、サーバの数がそれほど多くなくても

一定のワークフローを保証しやすくなります。

つまり

管理作業の共有、引き継ぎを楽にしてくれます。

もちろん独自タスクの管理のためには Ruby と Rake への理解を要求するので、楽になる一方ではありません。しかも Rake も Capistrano もそんなにドキュメントが充実しているわけでもありません。しかし、スクリプトを書いて自動化して、手作業によるミスを減らせるようにしてあるはずなのに、なんとなく属人的な作業が残っちゃう部分があって、なんか気持ち悪いなぁと感じているような場合には Capistrano の導入は十分に検討の価値があるんじゃないでしょうか。

超簡単な例

えーと概念の話からインストールの方法をすっ飛ばしていきなり実例に入ります。*4

カレントディレクトリに以下のような内容で Capfile という名前のファイルを作ってください。ここでログイン先のサーバのユーザー名、パスワードは一致しているものとします。

role :server, 'server1, 'server2'

set :user, 'user'
set :password, 'password'

desc "reporting disk usage with 'df -h'"
task :check_disk, :roles => :server do
  run 'df -h'
end

cap check_disk

と実行すると

 * executing `check_disk'
 * executing "df -h"
   servers: ["server1", "server2"]
   [server1] executing command
   [server2] executing command
** [out :: server1] Filesystem            Size  Used Avail Use% Mounted on
** [out :: server1] /dev/xvda1             32G   24G  7.2G  77% /
** [out :: server1] tmpfs                 201M     0  201M   0% /dev/shm
** [out :: server2] Filesystem            Size  Used Avail Use% Mounted on
** [out :: server2] /dev/mapper/XXX        17G   14G  2.1G  88% /
** [out :: server2] /dev/xvda1             99M   27M   67M  29% /boot
** [out :: server2] tmpfs                 181M     0  181M   0% /dev/shm
   command finished

みたいな結果が得られます。つまり、server1, server2 にログインして実際に df -h した結果をそのまま、Capistrano をインストールしたマシン上で確認できたということです。

どうです、なかなか面白くないですか。

情報収集が楽になるはず

これはちょっといきすぎてるかな?と思わなくもないのですが、cron ジョブの実行を Capistrano マシンに集中させることも可能ですね。こうすると

  • 個々のサーバで crond が不要
  • cron ジョブのレポートメールを Capistrano マシン上に集約可能
  • cron ジョブの様子を一カ所で確認できるので、スケジュールを考えやすくなる

というメリットがあります。もちろんデメリットや不安材料もあって、

  • ssh login のコスト
  • 長い時間掛かる仕事をさせたときの ssh connection はどうなる?

なんかが気になるところです。まだ見落としてることもあるかもしれません。

cron のレポートの受け取りが面倒くさい

ただ、cron はレポートのメールの受け取りが面倒だなと以前から感じていたので、この問題を解決しやすくなるとしたらとても嬉しいです。というのも、cron のレポートは基本的にローカルのアカウントにメールされるのですが、

どうやって読むの?

という問題がつきまといます。今思いつくのは

  1. 個々のサーバにログインして読む
  2. 個々のサーバに POP サーバ立てる
  3. forward する
  4. mail -> html -> feed 変換して feed reader で読む

くらいですかね。数が増えてくれば当然 1, 2 はナシだと思うんですが、

forward する場合、forward 先のサーバには SMTP サーバと SMTP の通る穴が必要

になります。これがまた悩ましい。メールサーバが LAN 内にあるなら LAN 内のレポートは文句なし LAN 内のメールサーバで処理すればいいです。でもインターネット向けに公開しているサーバのメールはどうしましょう? LAN 内のサーバ向けに forward ? fw で閉じてませんか? じゃあインターネット上の SMTP サーバに転送? OBP25 とかに引っかかりませんか? それにインターネット上に置いた SMTP サーバはあっという間に spam やエラーメールの嵐に飲み込まれてしまいます。すると今度は spam filter だ anti virus だ…。ふー。違うんだよ、オレはそんなことしたいんじゃないの。要するに

forward も意外に面倒なのです。

もう一つ、メールったってこんなの返信の必要もないし、みんな feed reader で読みたいなぁと以前から思っていました。実際、mail -> html -> feed 変換をしている人は見かけます。HTML にして URI が付けば内容の共有も楽です。*5しかしどうしても転送の部分がネックになります。各サーバで feed 吐いてそれpla で収集してもいいですけど、なんかそれもどうなんだと。

でも Capistrano からタスクを実行すれば、自動的に、少なくとも stdout や stderr の内容は取得できます。結果をファイルに落とすタイプでもファイルの転送が可能*6なのでそれを取得してくればオッケーです。

てことは、レポートの収集の部分は自動的にクリアしてしまいます。おう、なんかこれ面白そうじゃん。

できそうなことの一覧

クラスの一覧から一部を抜粋。

Capistrano::Configuration
Capistrano::Configuration::Actions
Capistrano::Configuration::Actions::FileTransfer
Capistrano::Configuration::Actions::Inspect
Capistrano::Configuration::Actions::Invocation
Capistrano::Configuration::Actions::Invocation::ClassMethods
Capistrano::Configuration::Callbacks
Capistrano::Configuration::Connections
Capistrano::Configuration::Execution
Capistrano::Configuration::Loading
Capistrano::Configuration::Loading::ClassMethods
Capistrano::Configuration::Namespaces
Capistrano::Configuration::Namespaces::Namespace
Capistrano::Configuration::Roles
Capistrano::Configuration::Servers
Capistrano::Configuration::Variables
Capistrano::Deploy
Capistrano::Deploy::Dependencies
Capistrano::Deploy::LocalDependency
Capistrano::Deploy::RemoteDependency
Capistrano::Deploy::SCM
Capistrano::Deploy::SCM::Accurev
Capistrano::Deploy::SCM::Accurev::InternalRevision
Capistrano::Deploy::SCM::Base
Capistrano::Deploy::SCM::Base::LocalProxy
Capistrano::Deploy::SCM::Bzr
Capistrano::Deploy::SCM::Cvs
Capistrano::Deploy::SCM::Darcs
Capistrano::Deploy::SCM::Git
Capistrano::Deploy::SCM::Mercurial
Capistrano::Deploy::SCM::None
Capistrano::Deploy::SCM::Perforce
Capistrano::Deploy::SCM::Subversion
Capistrano::Deploy::Strategy
Capistrano::Deploy::Strategy::Base
Capistrano::Deploy::Strategy::Checkout
Capistrano::Deploy::Strategy::Copy
Capistrano::Deploy::Strategy::Export
Capistrano::Deploy::Strategy::Remote
Capistrano::Deploy::Strategy::RemoteCache

いやーこうして見ると Deploy の充実っぷりがやはりすごいですね。Mercurial や Bzr なんて文字も見えるので、これらを使った deploy もできるんでしょう。

使えそうなリソース

Capistrano 自体が github でホスティングされているためか、github で検索するといちばんたくさん引っかかるようです。

あとはシステム管理系のレシピが載ってそうなところとか。まだあんまちゃんと見てないですけど。

最後に。

みんな、実際に試してオラにやり方を教えてくれ!

*1 当然、Ruby も必要

*2 これ recursive に取れないのかな? もしかして使ってる gem が古い?

*3 公開鍵認証を利用するための鍵作成には Putty などの ssh クライアントがたぶん必要です。

*4 実際、rubygems さえ動いていればインストールはそれくらい簡単です。

*5 例えば管理用のメールを複数人で受信していて、何か気になるアラートがあったとします。この情報を共有したいわけですが、メールを一意に特定するのは Message-ID です。しかし Message-ID の確認や検索の容易なメーラーは寡聞にして知りません。

*6 やり方はまだ分かってません!

本日のツッコミ(全1件) [ツッコミを入れる]

_ Johann [大変分かりやすいです。参考にさせていただきます。]


2015-12-18

_ CircleCIに最新のSQLite3をインストールした状態でsqlite3 gemを使う

ちょっと複数の問題が混ざっていて難儀したけど、切り分けたうえでタイトルの話が解決したのでナレッジをシャアさせていただきます。

まとめ

かっこつけて Tl; dr とか書く必要なくね? まとめでよくね?

  • ruby の native extension は gem のバージョンの他に build 前のソースのバージョンにも気をつける
  • ssh や伝統的なコンパイルの方法*1とか知ってると便利!
  • CI の整備をするのってやっぱアプリの開発とは違うノウハウが要るんだなぁ〜

じゃあ何が起きて何が分かったか順にいきましょう。れっつらごー。

activerecord-importを使ったらCircleCIでSyntax Error

activerecord で bulk insert をやりたくて activerecord-import を使ったんですよ。

ActiveRecord のバージョンによって対応してるバージョンが違うので、それに気をつけてインストールしましょうって程度で、開発自体は特に難しくない。サクサクと進んでテストも済んで、よしよしと思っていたんだけど、よしじゃあ pull-req ってみますかねと思ったところで、

ここで生成されるSQL

INSERT INTO "tables" ("id", column_name1, column_name2, ...)
            VALUES (NULL, value1, value2, ...)

が SyntaxError になってしまうという問題に遭遇。

しかも CircleCI でだけ。うへえ。

SQLite 3.7.11のinsert文拡張

SQLite Release 3.7.11 On 2012-03-20

ここに書かれている

  • Enhance the INSERT syntax to allow multiple rows to be inserted via the VALUES clause.

がポイント。つまり CircleCI の SQLite3 が 3.7.11 より古い可能性がある。*2

2015-12時点でCircleCIはUbuntu 12.04

CircleCI の環境はサイト上に記載されている。

Base

Our base image uses Ubuntu 12.04, with the addition of many packages commonly used in web development. Some specifics:

  • Architecture: x86_64
  • Username: ubuntu
  • Ubuntu 12.04 (precise)
  • Kernel version: 3.2
  • git 1.8.5.6
  • gcc 4.6
  • g++ 4.6
  • GNU make 3.81

via. https://circleci.com/docs/environment

各種言語のバージョン情報などはたんまりあるが、残念ながら SQLite3 に関する情報はない。はてどうするか。

CircleCIのbuild環境にsshでログインする

ここから急にサーバ管理方面の知識が必要になる。イマドキ(小規模な) Web アプリの開発や deploy に ssh は不要だと思ってたけど、CI のおまかせセットから外れるには力が必要なのだ。

CircleCI には build 環境に ssh で繋ぐ方法があり、それはちゃんとドキュメントに書かれている。

SSH access to builds - CircleCI

2015-12-18時点でまだサービスのデザイン変更にドキュメントが追従していないが、まぁやり方は一緒である。

ここで接続には GitHub に登録してある鍵を利用する のがポイント。

ssh 接続の際に何が起きてるかよく分からないという場合は -v オプションを重ね打ちするとよいぞ。今は Windows の人も openssh が使えるらしいので、ナレッジが共有できて便利ですね。

で、

sqlite3 --version

と叩くと 3.7.9 と返ってくる。間違いない、こいつだ。

そもそも native extension とは

SQLite3 に限らないんだけど、native extension とはざっくり言うと

Ruby と、 C などの Ruby の外の世界を繋いでいるもの

である。

この繋ぎ方に作法があり、SQLite3 で言うと

  1. SQLite3 の C言語のヘッダやコンパイル済みのライブラリを準備しておき
  2. `gem install` の際に Ruby とリンクする

という作業を行う。よく CentOS など yum の世界では

yum install sqlite-devel

Debian / Ubuntu 系の世界では

apt-get install libsqlite3-dev

しておけと StackOverflow などで Answer が出ているが、これは上の 1 の準備をしているという意味である。

つまり sqlite3 gem で言うと

  • sqlite3 gem のバージョンの他に SQLite3 本体のバージョンがある
  • CircleCI では SQLite3 本体のバージョンが古い
  • CircleCI の SQLite3 のバージョンを上げなきゃならない

Ubuntu 12.04のSQLite3を新しくするには

大きく二つ方法がある。

Debian 系の distro では apt でインストール可能なパッケージの配布元の設定をいじることで distro 標準のバージョンよりも新しいパッケージを入れることができる。これが一つ。

もう一つは cache と野良ビルドを使う 方法だ。

CircleCI でも apt-key から sources.list を更新してパッケージ全体を更新するというのはできなくもなさそうなのだが、そこ突っ込んで失敗すると時間の損失がでかそうだし、そもそも今やりたいのは CircleCI で使っている Ubuntu 全体の管理を刷新するということではなく、単に SQLite3 のバージョン上げろってことなので、ドキュメントや情報の揃っている、後者の方法を採用することにした。

誰か apt から新しいバージョンのインストールした方が簡単だよという手順を確立したら教えてください。

※ 古い話だと distro は Debian stable を入れておきながら一部のパッケージだけ testing から持ってくる、みたいなテクニックがあるのだが、そもそも Ubuntu って Debian testing ベースだし、いやいや、Ubuntu LTS ってもう次の 14.04 が出てからずいぶん経ってるよね、みたいなことを思いながら、粛々と古式ゆかしい作業に突入していくのであった。

CircleCIでSQLite3を野良ビルドする

ものによって気をつけるべきポイントは違うと思うが、SQLite3 の場合は面倒な依存もないのでとっても簡単。

https://www.sqlite.org/2015/sqlite-autoconf-3090200.tar.gz

からソースを取って来てビルドするだけ。こんな感じだ。

wget https://www.sqlite.org/2015/sqlite-autoconf-3090200.tar.gz
tar zxf sqlite-autoconf-3090200.tar.gz

cd sqlite-autoconf-3090200
./configure
make

コーヒーを抽出する前に終わる。

configure とか make とかイマドキだとやったことのない人も多いかもしれない。Web アプリ作るだけなら実際必要ない知識になりつつあるけど、こうして必要になるシーンもあったりするので、若い人も時間を見つけて「とりあえずコンパイルしてみた」みたいな経験をするのもよいことなのかもしれない。*3

逆に年寄りでサーバ分かるよと言いたい人はこういう形で経験を生かせるとより全体の幸福に貢献できるので、積極的にイマドキの環境を試すのがよいと思う。

make installとgem install

さて、上の手順では普通やるはずの作業を一つやってない。

make install

だ。これは文字通り今コンパイルしたツールを利用可能な状態にインストールする作業で、普通は root 権限が必要なので

sudo make install

と実行する。

結論から言うと結局この通りに実行するのだが、考えなければいけないのは

今やろうとしていることはbundle install

だということ。

というのも、実は bundle install に当たって以下のことを考える必要がある。

  1. CircleCI ではすでに SQLite 3.7.9 のライブラリがインストールされている
  2. gem install の際に標準ではない依存ライブラリの場所を指定する必要がある
  3. gem install のオプション指定を bundler に教えてやる必要がある
  4. その指定したい場所にヘッダとライブラリを置く必要がある
  5. gem install の際には gem install で標準的に想定しているライブラリやヘッダの配置があり、それに従っていないとすごく面倒

ふー。やっぱ野良は面倒だ。

/usr/localに入れる

前述の 1 と 4, 5 の課題を一気に解決するのは

sudo make install

すること。

Debian 系では apt でインストールするパッケージは /usr 以下に、野良で入れるものは /usr/local 以下に、というルールがあり、何も考えずに make install すると /usr/local 以下にさっきコンパイルした SQLite がインストールされる。*4以下のような感じだ。

/usr/local/include/sqlite3.h
/usr/local/lib/x86_64-linux-gnu/libsqlite3.a
/usr/local/lib/x86_64-linux-gnu/libsqlite3.la
/usr/local/lib/x86_64-linux-gnu/libsqlite3.so

ということで /usr 以下に SQLite 3.7.9 が、 /usr/local 以下に 3.9.2 がインストールされる。問題なく同居できる。

で、くり返すが大事なのは gem install 時にもこのような

{prefix}/include/
{prefix}/lib/

といった配置が期待されているということ。だからあとは bundle install 時に /usr 以下ではなく /usr/local 以下の SQLite3 をリンクしてくれるように教えてあげることができればオッケーだ。

gemに/usr/local以下のSQLite3を教える

ここが分かりにくい。native extension の作り方を知ってしまえばいいのだろうが、普通は native extention は作りたいんじゃなくて使いたいのだ。

とりあえず sqlite3 gem では `tasks/vendor_sqlite3.rake` の中にある `--with-opt-dir`が使える。具体的には

gem install sqlite3 -- --with-opt-dir=/usr/local

とすると目的を達成できる。

試しに上を実行して本当に新しいバージョンの SQLite3 を使っているかどうかは

ruby -e 'require "sqlite3"; p SQLite3::libversion'

で確認できる。

bundlerに/usr/local以下のSQLite3を教える

実際には CircleCI で動かすには普通は bundle install を利用して gem を入れているはず。gem コマンドに与えるオプションを bundle から指定するには

bundle config

コマンドを使う。

bundle config build.sqlite3 --with-opt-dir=/usr/local

とすると sqlite3 を build する際のオプションを指定できる。

CircleCIで野良ビルドしたアプリを効率的に利用する

さて、ここまでの処理を circle.yml から呼び出せるようにすると、

  • CircleCI で build する際に自動的に最新の SQLite3 をインストールして
  • それを利用して bundle install して
  • テストを実行する

ことができるようになるわけだが、普通に考えて すごく重たい ことは想像に難くない。

そこで cache を利用する。

cacheの指定とpre build処理

CircleCI の build 時に事前の処理と、その際生まれた成果物を再利用できるように cache するディレクトリを指定することができる。

具体的にはこんな感じ。

circle.yml

dependencies:
  cache_directories:
    - "~/sqlite3"
  pre:
    - ./_circle_script_install_sqlite3

注意しなければいけなのは ~ による $HOME の展開を YAML 上で期待する場合は quote する必要がある点。ちゃんと本家のドキュメントでは quote されているのだが、日本語のブログエントリを探してると、ここを検証せずに quote なしの記述を載せている場合がある。

本家のドキュメントを当たるのが何よりも基本

なので、ちゃんとドキュメント探そう。ついでに sqlite3 のインストールと bundle config 用のスクリプトも載せておく。

_circle_script_install_sqlite3

#! /bin/sh

if [ ! -e ~/sqlite3 ]; then
    mkdir -p ~/sqlite3
    cd ~/sqlite3

    wget https://www.sqlite.org/2015/sqlite-autoconf-3090200.tar.gz
    tar zxf sqlite-autoconf-3090200.tar.gz

    cd sqlite-autoconf-3090200
    ./configure
    make
fi

cd ~/sqlite3/sqlite-autoconf-3090200
sudo make install

bundle config build.sqlite3 --with-opt-dir=/usr/local

cache を使うので sqlite3 内の make の成果は消えない。つまり、コンパイルに掛かる時間はゼロになる。ただし、ライブラリのインストールは毎回行っている。

わざわざ毎回 make install と bundle config を叩いているのは、どうにも build が安定しなかったためで、本当は要らないかもしれない。

これで快適CircleCI + 最新SQLite3生活のできあがり

というわけで無事 CircleCI で SQLite 3.9.2 を使って activerecord-import を使ったコードのテストが通るようになりました。長かった。

ということでもう一度まとめ。

gem について

  • native extension は gem のバージョンだけでなく、利用しているソースのバージョンも大事

CircleCI について

  • build 環境に ssh でログインできる
  • 独自アプリのインストールができる
  • cache をうまく使えば独自アプリインストールをスキップして build 時間を削減できる

その他

  • C で書かれたプログラムの手動コンパイルの方法、Un*x系 のディレクトリの配置ルールなど古い知識も役に立つ
  • build 環境もコードで制御するとさらに幸せな CI 生活を送れる

おっさんの経験が不要になる環境は揃ってきているが、おっさんはおっさんで貢献できる。ちゃんと「枯れる」ノウハウ、スキルを身につけていきたいもんだなと改めて思ったのでした。

*1 ./configure; make; make install

*2 ここにそんなすぐたどり着けるかというと、そこは微妙。いろいろ試行錯誤は必要だと思う。

*3 Make を知っておくとイマドキのタスクランナーの話題を理解しやすいかも

*4 この辺は distro というか OS ごとにルールが決まっている。