gitosis を使ってみた

By | 2011年1月21日

久しぶりのエントリーと思ったらはや1年をこえてた。。。
ちょっとびっくりしつつ、これからはなるべく書いていこうと思う2011年初冬。

で、さっそく自宅サーバーのHDDがふっとんだので
サーバーを再構築。
その際にリポジトリを svn から git へ移行しました。

前々から gitosis は便利そうだなと思ってたのでさっそく導入。
便利そうと思われるのは以下の点

1. gitosis の設定自体も git リポジトリで管理。ローカルに残るからバックアップにもなる
2. リポジトリ毎のアカウント権限の設定、新規リポジトリの作成が簡単
 わざわざサーバーにログインして作業する必要がない
3. ssh経由で取得するリポジトリの設定がすぐできる

gitosisをインストール

OS は Ubuntu 10.04 です。
python2.6 では gitosis-init が動かないという記事をみたんですが
そんなことなく動きました。

$sudo apptitude install git-core gitosis
$sudo -u gitosis -H gitosis-init < id_rsa.pub  
(※) .authrized_keys みたいに複数わたすと一番上のみ登録される

これで設定終了。
簡単すぎ!!!

さっそくSSHできるかの確認。
鍵を登録したのが localhost のアカウントの公開鍵なのでそのまま SSH を実行する。

PTY allocation request failed on channel 0

と返ってくればOK.

というわけで、設定ファイル等が入ったリポジトリをさっそく取得

$git clone gitosis@localhost:gitosis-admin.git
$cd gitosis-admin.git
$tree
.
├── gitosis.conf            # リポジトリ毎の設定
└── keydir                    # 公開鍵をここに追加
    └── dealforest@localhost.pub
            ~~~~~~~~~~~~~~~~
               .pub をぬいた分がアカウント名
 
$cat gitosis.conf
[gitosis]
 
[group gitosis-admin]
writable = gitosis-admin
members = dealforest@localhost      # コミット権限のあるアカウント
readonly  = ....                                 # readのみ可能
 
それぞれ複数記入する際は空白で区切って入力すればよい。

さっそくリポジトリの追加

その前に localhost にしかアカウントがないのは不便なので鍵を追加。
“gitosis-admin/keydir/dealforest@milan.pub” に公開鍵を置く。
ファイル名は適当に変えて大丈夫です。

gitosis.conf に以下を追加して commit して push!

$cat gitosis.conf
[group private-project]
writable = private/project
members = dealforest@localhost
 
$git commit -a -m 'add repository "private-project"'
$git push origin master

次にリポジトリを作成 です。

$mkdir project.git
$git init
$touch README
$git add .
$git commit -m 'first commit'

あとは remote の設定をして push!

$git remote origin ssh://gitosis@[サーバーIP]/private/project.git
$git push origin master

[gitosis] にloglevel = DEBUGを追加すると
詳細情報がみれるためうまくいかない時に便利

gitwebのインストール

ここまで来たら web からもみたいなとおもい
ついでに gitweb もインストールしてみました。

$sudo aptitude install gitweb
$cat /etc/gitweb.conf
# $projectroot = "/var/cache/git";
$projectroot = "/srv/gitosis/repositories";    # gitosis で管理してるディレクトリを指定

apache の conf がこんな感じ

 DocumentRoot /usr/lib/cgi-bin
<Directory />
    Options         FollowSymLinks
    AllowOverride   None
</Directory>
 
<Directory /usr/lib/cgi-bin>
    Options         ExecCGI
    AddHandler      cgi-script .cgi
    AllowOverride   None
    DirectoryIndex  gitweb.cgi
    Order           allow,deny
    allow from      all
</Directory>

いい感じ!

参考資料

Ubuntuサーバにgit/gitosis/gitwebを入れてみる
gitosis – Git リポジトリ群の管理とアクセス制御 vol.2

FileHandle に書き込んでいたデータの出力先を変数にしてくれるIO::Scalar

By | 2009年5月1日

タイトルの通り今回したかったのはファイルハンドルを使って
ファイルへ出力していたコードの出力先を変数にしたかった。

そういうことをしてくれる小粋なモジュール IO::Scalar を使って対応しました。
これがまた便利で、数行書き換えるだけでよくてパフォーマンスは使う前と後で、それほど差異はありませんでした。

通常の FileHandle を使ったコード

#!/usr/bin/perl

use strict;
use warnings;

open my $fh, '>', 'file' or die $!
print $fh 'hoge'; #この時点で file とう名前のファイルがカレントディレクトリにつくられます。

1;

IO::Scalar を使って出力先を変数にしたコード

#!/usr/bin/perl

use strict;
use warnings;
use IO::Scalar;

my $file;
my $out;
{
    my $fh = IO::Scalar->new(\$out);
    local *F = $fh;
    $file = *F;
    print $file "hoge\n";
}
warn $out;

1;

で、調べていくと IO::String というモジュールも同じようなことをしてくれることを知った。
ちょっと試してみたけどインターフェースはさほどかわりない感じ。
というわけでベンチ。

           Rate IO_STRING IO_SCALAR
IO_STRING 210/s        --      -44%
IO_SCALAR 373/s       77%        --

見た通り IO::Scalar の方がはやいですね。
試したコードはこれ。

#!/usr/bin/perl

use strict;
use warnings;

use IO::String;
use IO::Scalar;
use Benchmark qw/cmpthese/;

my @data = map { int rand 1000 } 1..1000;

cmpthese(10000, {
        IO_STRING => \&with_io_string,
        IO_SCALAR => \&with_io_scalar,
});

sub with_io_scalar {
    my $output;
    my $ios = IO::Scalar->new(\$output);
    local *STDOUT = $ios;
    print $_ for @data;

#    warn $output;
}

sub with_io_string {
    my $output;
    my $ios = IO::String->new(\$output);
    local *STDOUT = $ios;
    print $_ for @data;

#    warn $output;
}

1;

参考資料

IO::Scalarで色々
IO::scalarでIOのキャプチャ

snippetsEmu から snipMate に移行したまとめ

By | 2009年4月14日

id:dann さんの記事 「snipMateのsnippetが書きやすい件」snipMate.vim が紹介されてて試してみた。
snipettsEmu.vim は snippets の追加がめんどくさかったってのもあるし
入力がタイポしてたりすると編集後に次の場所に移動できなかったりとか

<h1>(1)</h1>
(2)

(1)入力後 => (2)に移動といったことをしようとすると html_snippets.vim を書き直す必要があった。
snipMate は sunppets の追加が簡単そうだったので乗り換えてみた。

インストール

snipMate.vim をダウンロードしてきて
.vim ディレクトリ以下で解凍すれば終了。
使い方は snipettsEmu と同じです。

snippetsの構造

$ tree html
snippets
|-- html.snippet <- filetype
 
$ tree html
snippets
|-- html <- filetype
    |-- body.snippet <- trigger
    `-- h1.snippet

html.snippets

snippet body <- trigger
    <body>
        ${1}
    </body>
snippet h1 <- trigger
    <h1>${1}</h1>
    ${2}

body.snippet

<body>
${1}
</body>

h1.snippet

<h1>${1}</h1>
${2}

この2つの構造は全く同じ意味です。
つまりは filetype ベースで trigger を作成しておけば良いということですね。
少しだけ .snippets の書き方の説明をしておきます。

${1} : 最初に入力する単語。デフォルトのままだと <tab> を入力すると ${2} に移動します。
${1:hoge} : デフォルトで hoge という単語が入力されている状態になります。
$1 : ${1} で入力された値と同期されます。

このように最初のインデントが必須。

trigger.snippets の場合は

<h1>${1}</h1>
${2}

このように実際に補完される文字をファイルに書いておけばいいから分かりよい。
ただ、ファイルが増えまくるのもどうかとも思うが。
自分の好きな方で filetype.sunippet もしくはディレクトリ構造に分ければいいと思う。

snippetが複数マッチする場合

この機能がかなり便利。

[dealforest@imac-local] tree html
snippets
|– html
|– doctype
|– HTML.snippet
`– XHTML.snippet

といった構造だとする。
この場合に hoge.html を開き doctype を入力し を実行すると

1. HTML
2. XHTML
Type number and <enter> or click with mouse (empty cancels):

とう画面が表示されるので 2 と入力すると XHTML の snippet が補完される。
ちなみにこれは html.snippets でいうと

snippets doctype HTML
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""
    "http://www.w3.org/TR/html4/loose.dtd">
snippets doctype XHTML
     <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
     "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

と同じこと。

補完を tab から c-b に変更

.vim/after/plugin/snipMate.vim

-ino <silent> <tab> <c-r>=TriggerSnippet()<cr>
-snor <silent> <tab> <esc>i<right><c-r>=TriggerSnippet()<cr>
+ino <silent> <c-b> <c-r>=TriggerSnippet()<cr>
+snor <silent> <c-b> <esc>i<right><c-r>=TriggerSnippet()<cr>

.vim/plugin/snipMate.vim

s/<tab>/<c-b>/

document には.vim/after/plugin/snipMate.vim だけ変更するといけるって書いてるけどそれだけじゃ駄目。
.vim/plugin/snipMate.vim の方も変更してやらないとたまに動かなくなるので注意。
<tab> ってハードコードされてた。。。。

tips

コマンド実行

snippet date
    `system("date +%Y-%m-%d")`

ファイル名に変換

snippet constructor
    public `Filename()`() {
    }

こんなことも可能。おほー

TT, perl の snippet を移行した

snippetsEmu で使わせてもらってた snippet を、せっかくなんでそのまま snipMate に移行しました。
ちなみに使用していた snippet は CatalystとTT用snippetsEmu.vim設定 です。
id:spiritloose さんのスニペットには本当にいつも助けられていました。感謝感謝。

tt2.snippet

snippet class
	[% USE ${1:class} = Class('${2:ClassName}') %]
	${3}
snippet url
	[% USE ${1:name} = url('${2:path}') %]
	${3}
snippet linkto
	<a href="[% c.uri_for('${1:path}', ${2:param}) %]¥">${3:label}</a>
	${4}
snippet if
	[% IF ${1:condition} -%]"
	${2}
	[% END -%]
	${3}
snippet ife
	[% IF ${1:condition} -%]
	${2}
	[% ELSE -%]
	${3}
	[% END -%]
	${4}
snippet ifee
	[% IF ${1:condition1} -%]
	${2}
	[% ELSIF ${3:condition2} -%]
	${4}
	[% ELSE -%]
	${5}
	[% END -%]
	${6}
snippet unless
	[% UNLESS ${1:condition} -%]
	${2}
	[% END -%]
	${3}
snippet for
	[% FOR ${1:var} = ${2:list} %]
	${3}
	[% END -%]
	${4}
snippet foreach
	[% FOREACH ${1:var} = ${2:list} %]
	${3}
	[% END -%]
	${4}
snippet while
	[% WHILE (${1:var} = ${2:rs}.next) -%]
	${3}
	[% END -%]
	${4}
snippet switch
	[% SWITCH ${1:var} -%]
	${2}
	[% END -%]
	${3}
snippet case
	[% CASE ${1:var} -%]
	${2}
snippet include
	[% INCLUDE '${1:file}' %]
	${2}
snippet process
	[% PROCESS '${1:file}' %]
	${2}
snippet macro
	[% MACRO ${1:name}(${2:arg}) BLOCK %]
	${3}
	[% END %]
	${4}
snippet var
	[% ${1:var} %]
	${2}
snippet hvar
	[% ${1:var} | html %]
	${2}
snippet hlvar
	[% ${1:var} | html | html_line_break %]
	${2}
snippet null
	[%- FILTER null -%]
	${1}
	[%- END -%]
	${2}

perl.snippet

#perl
snippet dump
	use Data::Dumper; warn Dumper ${1:$var};
	${2}
snippet say
	print ${1:$var}, "¥n";
	${2}
snippet self
	my $self = shift;
	${2}
snippet data
	my $data = do {
		local $/;
		<data>
	};
	${1}
snippet argf
	while (<>) {
		chomp;
		${1}
	}
	${2}
snippet isa
	if (blessed ${1:$var} and ${2:$var}->isa('${3:Class}')) {
		${4}
	}
	${5}
snippet readcsv
	use IO::File;
	use Text::CSV_XS;
 
	my $fh = IO::File->new('${1:filename}') or die 'cannot open file.';
	my $csv = Text::CSV_XS->new({ sep_char => "¥t", binary => 1 });
	until ($fh->eof) {
		my $cols = $csv->getline($fh);
		unless ($cols) {
			warn $csv->error_diag;
			next;
		}
		my (${2}) = @$cols;
	}
	$fh->close;
	${3}
 
#class-C3
snippet next
	$self->next::method(@_);
	${1}
snippet maybe
	$self->maybe::next::method(@_);
	${1}
 
#Catalyst
snippet debug
	$c->log->debug('${1:[ debug ]}: '. ${2:$var});
	${3}
snippet warn
	$c->log->warn('${1:[ warn ]}: '. ${2:$var});
	${3}
snippet dumper
	$c->log->dumper('${1:[ dumper ]}: '. ${2:$var});
	${3}
snippet model
	$c->model('${1:model}')
	${2}
snippet view
	$c->view('${1:view}')
	${2}
snippet template
	$c->view('View::TT')->template('${1:name}');
	${2}
snippet config
	$c->config->{${1:name}}
	${2}
snippet controller
	sub ${1:func} : ${2:Attribute} {
		my ($self, $c) = @_;
		${3}
	}
	${4}
snippet begin
	sub begin : Private {
		my ($self, $c) = @_;
		${1}
		1;
	}
	${2}
snippet auto
	sub auto : Private {
		my ($self, $c) = @_;
		${1}
		1;
	}
	${2}
snippet detach
	$c->detach('${1:name}');
	${2}
snippet forward
	$c->forward('${1:name}');
	${2}
snippet stash
	$c->stash->{${1:var}}${2}
snippet flash
	$c->flash->{${1:var}}${2}
snippet session
	$c->session->{${1:var}}${2}
snippet sstash
	$c->stash->{${1:var}} = ${2};
	${3}
snippet sflash
	$c->flash->{${1:var}} = ${2};
	${3}
snippet ssession
	$c->session->{${1:var}} = ${2};
	${3}
snippet rs
	$c->model('DBIC::${1:Source}')
	${2}
snippet redirect
	$c->res->redirect($c->uri_for('${1:uri}'));
	${2}
snippet param
	$c->req->param('${1:param}')
	${2}

snippetsEmu の不便だったとこがなくなったー
相当快適になった。
ただどうしても分からなかったのが外部で定義した snippet を include するやり方がわからなかった。
そのため .tt の場合には filetype を tt2.html とすることで回避した。

perl でシリアライズのベンチマークをとってみた

By | 2009年4月10日

Perl でシリアライズの方法が色々あるのでちょっとベンチマークをとってみた。
ちなみに試したのは Storable, FreezeThaw, Data::Dumper, XML::Dumper の4つ。
結果だけを先にいうと一番のおすすめは Data::Dumper でファイルに出力し、eval するのが一番よさげ。

ベンチマークをとったコード(シリアライズ)

#!/usr/bin/perl
 
use strict;
use warnings;
use Benchmark qw/cmpthese/;
 
use Storable;
use FreezeThaw;
use Data::Dumper;
use XML::Dumper;
 
$| = 1;
 
package Human;
use base qw/Class::Accessor::Fast/;
__PACKAGE__->mk_accessors( qw/name email key/ );
 
package main;
 
my $human = new Human();
$human->name('dealforest');
$human->email('dealforest.net@gmail.com');
 
open my $store, '>', 'store';
open my $dumper, '>', 'dumper';
open my $freezethaw, '>', 'freezethaw';
open my $xml, '>', 'xmldumper.xml';
 
my $dump = new XML::Dumper;
 
cmpthese(50000000 ,{
        dumper => &data_dumper,
        store_fd => &storable_store,
        freeze => &freezethaw_freeze,
        pl2xml => &xmldumper_pl2xml,
});
 
close $store;
close $xml;
close $dumper;
close $freezethaw;
 
sub storable_store {
    Storable::store_fd $human, $store;
}
 
sub data_dumper {
    print $dumper Dumper $human;
}
 
sub freezethaw_freeze {
    print $freezethaw FreezeThaw::freeze $human;
}
 
sub xmldumper_pl2xml {
    print $xml $dump->pl2xml($human);
}
 
1;

ベンチマークの結果(シリアライズ)

                Rate   pl2xml   freeze   dumper store_fd
pl2xml    68493151/s       --     -29%     -41%     -51%
freeze    96153846/s      40%       --     -17%     -31%
dumper   116279070/s      70%      21%       --     -16%
store_fd 138888889/s     103%      44%      19%       --
 
(※)ベンチの結果はカオスなくらい毎回かわりますw
そのためどらが一概にはやいのか良くわからいです。。。
平均的にみたらこれかなってのをだしてます。

ベンチマークをとったコード(デシリアライズ)

#!/usr/bin/perl
 
use strict;
use warnings;
use Benchmark qw/cmpthese/;
 
use Storable;
use FreezeThaw;
use Data::Dumper;
use XML::Dumper;
 
$| = 1;
 
my $xmldump = new XML::Dumper;
 
cmpthese(100000, {
        dumper => sub {
            open my $fh, '<', 'dumper';
            my @a = <$fh>;
            my $VAR1;
            eval(join '', @a);
            close $fh;
        },
        fd_retrieve => sub {
            open my $fh, '<', 'store';
            Storable::fd_retrieve($fh);
        },
        freeze => sub {
            open my $fh, '<', 'freezethaw';
            my $a = <$fh>;
            FreezeThaw::thaw($a);
            close $fh;
        },
        pl2xml => sub {
            open my $fh, '<', 'xmldumper.xml';
            my @a = <$fh>;
            $xmldump->xml2pl(join '', @a);
            close $fh;
        },
    }
);
 
1;

ベンチマークの結果(デシリアライズ)

               Rate      pl2xml      freeze      dumper fd_retrieve
pl2xml       2703/s          --        -71%        -81%        -90%
freeze       9183/s        240%          --        -35%        -66%
dumper      14025/s        419%         53%          --        -47%
fd_retrieve 26667/s        886%        190%         90%          --

まとめ

シリアライズするコストはどれも似たような感じ。
デシリアライズのコストは意外に XML::Dumper がはやかった。
Storable がおそかったのは少しびっくりした。

デシリアライズのコストは Storable が一番。その次に Data::Dumper がはやかった。
ただ XML::Dumper は文字データしか扱えない。バイナリ絡むと無理。
FreezeThaw も若干微妙。

その辺で一番便利だったのが Data::Dumper だった。
swfをパースしたインスタンスでも復元できた。
つまりは Data::Dumepr を選んどくとが一番幸せになれそう。

追記: 2009-04-10T03:18:27+00:00
Storable は GLOB をシリアライズできないみたい。

Can't store GLOB items

ってエラーがでた。