JAMADAM.COM

RSS Subscribe to my RSS feed

Stripe Calendar

Jul, 2009
Jun 10 11 12 131415161718192021 22 23 24 25 2627282930 Jul 123 4 5

Entry: 非root権限でCPANモジュールをインストールする(焼増し)

非root権限でCPANモジュールをインストールする(焼増し)

Initial post: 2009.07.04 | Last modified: 2009.07.04

非root権限でCPANモジュールを使う方法を調べた。Debian lenny(最小限のセットアップ)にて。2006年頃までにすべての情報が出尽くしてるのに何を今さら。

cpanの初期設定をする。設定項目「makepl_arg」はモジュールのインストール先ディレクトリ。PREFIX=~/perlと記載することで~/perl下に配置される。設定ファイルは下記のように書き換える。

$ vi ~/.cpan/CPAN/MyConfig.pm

- 'makepl_arg' => q[],
+ 'makepl_arg' => q[PREFIX=~/perl],

依存関係のあるモジュールを芋づる式にインストールするとき、後に入るモジュールのテストスクリプトが、直前の依存モジュールをincludeできなくてつまづく。これを回避するため、ユーザーの環境変数PERL5LIBにパスを設定する。~/.bashrcに下記を追記すれば楽。どうやらものによって下記のような2つのパスにインストールされるらしい。

$ vi ~/.bashrc

export PERL5LIB=~/perl/lib/perl/5.10.0:~/perl/share/perl/5.10.0

最初の「~/perl」は先ほどMyConfigのmakepl_argに追加したパス、それ以降は環境に依存するようなので一度失敗してみてパスを確認して再試行。もっといい方法ないのか。そのためのlocal::libなのかどうなのか、またの機会に調べてみよう。

参考サイト
一般ユーザ環境におけるCPANモジュールの使い方
Using CPAN with a non-root account

Entry: 自作バックアップスクリプトは高速化しなかった

自作バックアップスクリプトは高速化しなかった

Initial post: 2009.06.25 | Last modified: 2009.06.25

昨日書いたPerlの差分バックアップスクリプトは職場では高速化の効果はほとんどなかった。まあ、予想はしていたけど、遅いのはnfsがボトルネックだったのだ。nfsの速度対策はもう済ませたしなあ。ssh経由のリモート機能つけるかな。ていうか、この地味な趣味、そろそろやめるかな。

Entry: Perlで差分バックアップスクリプト

Perlで差分バックアップスクリプト

Initial post: 2009.06.24 | Last modified: 2009.06.24

2006年にpdumpfsっぽいPerlスクリプトを書いた。glastreeの存在は知っていたけど、敢えて自分で作ってみた。それ以来、仕事でもプライベートでも重宝していたんだけど、最近問題発生。職場のファイルサーバーには百万越えのファイル数があって、毎日数万の差分が発生し、バックアップに5時間かかっていた。こいつはまずいということで手直しした。結果、取りあえず、自宅では以前の10倍高速になった。

ちなみに、今回はglastreeのソースを追って参考にしてみたらほぼ同じ内容になってしまったんだけど、glasstreeとの違いは下記のとおり。

  • バックアップの管理が日付に依存しないので任意の頻度(例えば2時間おきとか)で実行できる
  • コピーされたログを残す
  • コアモジュール以外に依存しない
  • 差分がない場合はバックアップを自動削除

ログが残るってのはなかなか便利です。差分リスト=作業履歴なので。

使い方

perl ddump.pl [バックアップ対象] [保存場所]

ソース

use strict;
use warnings;
use utf8;
use English;
use Getopt::Long;
use File::stat;
use File::Copy;
use File::Path;

binmode(STDIN,  ":utf8");
binmode(STDOUT, ":utf8");
binmode(STDERR, ":utf8");
use open IO  => ":utf8";

use vars qw(%QUERY %stat_idx); # 設定
use vars qw($log $copy_count $file_count $symlink_count); # ログ関係変数
use vars qw($tgt_path $newdir $olddir); # ディレクトリ

main();

sub main {
    %stat_idx = ('mode' => 2, 'size' => 7, 'utime' => 9);
    
    %QUERY = ('mode' => 1, 'size' => 1, 'utime' => 1);
    GetOptions(\%QUERY, 'mode=s', 'size=s', 'utime=s');
    
    ### 引数の整備と検証
    $ARGV[0] = &fixPath($ARGV[0]);
    $ARGV[1] = &fixPath($ARGV[1]);
    -d $ARGV[0] or die "$ARGV[0] not found";
    -d $ARGV[1] or die "$ARGV[1] not found";
    
    ### 引数を分離
    ($tgt_path, my $tgt_dir) = ($ARGV[0] =~ m!(.*)?/([^/]+)$!);
    
    ### 前回バックアップの時刻ディレクトリ名を取得
    if (opendir(DIR, "$ARGV[1]")) {
        my @dirs = sort grep{ -d "$ARGV[1]/$_" && /^[^.]/} readdir( DIR );
        close(DIR);
        $olddir = "$ARGV[1]/". (pop(@dirs) or '');
    }
    
    ### 時刻ディレクトリの作成
    my ($sec, $min, $hour, $mday, $mon, $year) = localtime($BASETIME);
    my $new_time =
        sprintf('%04d%02d%02d%02d%02d%02d', $year+1900, $mon+1, $mday, $hour, $min, $sec);
    $newdir = "$ARGV[1]/$new_time~";
    umask 0;
    mkdir($newdir, 0755) or die "cannnot make $newdir";
    
    ### ログファイル生成
    open($log, ">>$newdir/ddumplog.txt") or die "cannnot make log file";
    print $log <<EOF;
-----------------------------------------------------------------
-- ddump -- $new_time
-----------------------------------------------------------------
EOF
    
    ### ログ記録用変数
    $copy_count = 0;
    $file_count = 0;
    $symlink_count = 0;
    
    ### バックアップ
    &backup($tgt_dir);
    
    ### ログファイルに結果出力
    print $log "$copy_count/$symlink_count/$file_count (Copyed/symlink/Total)\n";
    print $log (time() - $BASETIME). "sec passed\n";
    close($log);
    
    if (! $copy_count) {
        ### コピーなしならディレクトリ削除
        rmtree($newdir);
    } else {
        ### ファイル名確定
        rename($newdir, substr($newdir, 0 ,length($newdir) - 1));
    }
}

### --------------------------------------------
### 再帰的ディレクトリバックアップ
### --------------------------------------------
sub backup {

    my $cwd = shift;
    my $tgt_cwd = "$tgt_path/$cwd";
    my $old_cwd = "$olddir/$cwd";
    my $new_cwd = "$newdir/$cwd";

    ### ディレクトリの作成
    &copydirstat($tgt_cwd, "/$new_cwd");

    ### カレントディレクトリ内の全ファイルを配列に格納
    opendir(DIR, $tgt_cwd) or return 0;
    my @files_and_dirs = readdir(DIR);
    close(DIR);

    my @files = grep { -f "$tgt_cwd/$_" or -l "$tgt_cwd/$_" } @files_and_dirs;
    
    ### @files_and_dirsのうち、ファイルを処理
    foreach my $a_file (@files) {
        my $old_file = "$old_cwd/$a_file";
        my $new_file = "$new_cwd/$a_file";
        my $tgt_file = "$tgt_cwd/$a_file";
        my $command = 1; # 0: nothing, 1: hard link 2: copy

        if (-l $tgt_file) {
            symlink(readlink($tgt_file), $new_file);
            $symlink_count++;
            $command = 0;
        }

        elsif (-f $old_file) {
            my $old_stat    = stat($old_file);
            my $crnt_stat   = stat($tgt_file);

            ### 更新ありならコピー
            foreach my $key (keys %stat_idx) {
                if ($QUERY{$key} and
                    $old_stat->[$stat_idx{$key}] ne $crnt_stat->[$stat_idx{$key}]) {

                    $command = 2;
                    last;
                }
            }
        } else { ### ファイルがなければコピー
            $command = 2;
        }

        ### コピー
        if ($command == 2) {
            copystat($tgt_file, $new_file);

            $copy_count++;

            ### ログ出力
            utf8::decode($new_file);
            print $log "$new_file\n";
        }

        ### ハードリンク
        elsif ($command == 1) {
            link($old_file, $new_file);
        }

        $file_count++;
    }

    ### @files_and_dirsのうち、ディレクトリを再帰処理
    my @dirs = grep { -d "$tgt_cwd/$_"
                    and not -l "$tgt_cwd/$_"
                    and $_ ne '.'
                    and $_ ne '..' } @files_and_dirs;

    foreach my $a_dir (@dirs) {
        &backup("$cwd/$a_dir") or print "Error at $cwd/$a_dir\n";
    }

    return 1;
}

### --------------------------------------------
### 属性丸ごとファイルコピー
### --------------------------------------------
sub copystat {
    my ($from, $to) = @_;
    my $stat = stat $from;

    copy($from, $to);
    chown($stat->uid, $stat->gid, $to) if $EUID == 0;
    chmod($stat->mode, $to);
    utime($stat->mtime, $stat->mtime, $to);
}

### --------------------------------------------
### 属性真似てディレクトリ作成
### --------------------------------------------
sub copydirstat {

    my ($from, $to) = @_;
    my $stat = stat $from;

    mkdir $to, 0555;
    chown ($stat->uid, $stat->gid, $to) if $EUID == 0;
    chmod ($stat->mode, $to);
    utime ($stat->mtime, $stat->mtime, $to);
}

### --------------------------------------------
### ファイルパスの整備
### --------------------------------------------
sub fixPath {
    my $in = $_[0];
    $in =~ s!^!\./! unless ($in =~ m!^\.*/!);
    $in =~ s!/$!!;
    return $in;
}

 

Entry: OSC行ってきた

OSC行ってきた

Initial post: 2009.06.22 | Last modified: 2009.06.22

OSC行ってきた。朝から晩までセミナー三昧。

一番面白かったのはPostgresqlで全文検索というやつでした。to_tsvectorってのを使うことでlikeでマッチングするより速度が100倍(!)っていうデモをやってました。バージョン8.3からって言ってたかな。

その他にはFirefoxの中の人のセミナーでは、オープンソースの基礎知識的な話題もあって、今さら人には聞けない系の知識を収集できた。Netscapeがブラウザのソースを公開する際に、フリーウェアという名称の代替えとしてオープンソースと呼称したのがOSSの始まりだったとか、GIFのサブマリン特許の話、動画を巡る同様の問題を回避する取り組み->Firefox3.5という流れ。

OpenOffice Baseに関するセミナーも面白かった。まだ、MS Accessの代替にはならないけど、がんばってますって話。なんか、自分には何かできることがあるだろうか、なんて発想が自然と湧いてくるいい内容でした。

最後にAndroidのアプリ開発に関するセミナー。何らかのトラブルでうまく進行してなかったみたいだけど、人が開発してる様子をリアルに眺めるだけでも刺激的。そして、となりの席にリアル兄がいたという偶然。

その他にもサーバー系とネットワーク系のセミナーも受けたけど、全く理解できなくて少し凹んだ。サーバーマシントラブルのほとんどはホコリが原因だという話だけがためになった。

Entry: text-overflow:ellipsis

text-overflow:ellipsis

Initial post: 2009.06.21 | Last modified: 2009.06.22

以前にこんなエントリ書いたり、こんなjQueryプラグイン作ったりしたけど、それってCSSだけでできるんじゃん!

http://www5e.biglobe.ne.jp/~access_r/hp/css/css_text_019.html

text-overflow
テキストがオーバーフロー(領域を超えてしまう事)する際にオーバーフローしたテキストを「...」で省略することが出来ます。

しかも属性名と値などのキーワードも思い描いたまんまじゃん。ただし、省略記号を有効にする指定はtext-overflow: ellipsis;だ。以前にもちゃんとググったつもりだったけど、英語の情報無視してたかなあ。

ただしFirefoxは未対応なので依然としてJavascriptでのハックは必要。また、text-overflowはIEのみの対応のようで、SafariやOperaはそれぞれの拡張属性を併記して対応できる。

a.width-limited {
    display:block;
    overflow: hidden;
    white-space:nowrap;
    -webkit-text-overflow: ellipsis; // Safari
    -o-text-overflow: ellipsis; // Opera
    text-overflow: ellipsis; // IE
}

Entry: ブックマーク

Entry: Javascriptオフ対策、その2

Javascriptオフ対策、その2

Initial post: 2009.06.12 | Last modified: 2009.06.12

検索とタグクラウドもノースクリプトで利用できるようにした。ページナビゲーションはまだない。

JS用に用意した部品のDOMをNoscriptな人に見せないために、最初は<script></script>内に書けばいいのかと思ったら失敗。<script>タグは<noscript>タグのnotでは全然なかったのだ。考えたこともなかったけど、<script>タグ内にはスクリプトしか書いちゃいけない、とのこと。今さらながら。

スクリプト用のDOMはスクリプトで書くしかないのかと思い、document.writeの列挙が頭をよぎったものの、メンテナンス性に配慮してjQueryのappendだのprependだののDOM操作で何とかする。それでも、文字のエスケープの問題もあるし、本来HTMLで書くべきものをJavascriptで書き出すのはやはり手間がかかる。でもまあいいか。

と思っていたのが昨日の話で、今日、あっけない結論に達する。まあ、ここに書くまでもないことかも。

<div class="dom_for_script" style="display:none"></div>
<script type="text/javascript">
//<![CDATA[
$(".dom_for_script").show();
//]]>
</script>

Entry: Javascriptオフ対策、少しした

Javascriptオフ対策、少しした

Initial post: 2009.06.11 | Last modified: 2009.06.11

Javascriptオフ対策、第一弾。エントリーウィジェット毎のタブ表示はJavascriptオフの人には非表示とし、代わりに最低限のサブコンテンツをベタに並べた。これで、少しだけ静的リンクでの自由度が広がった。

もともと非AJAXなブログだったのでサーバーサイドは変更の必要はないんだけど、クライアントサイドの帳尻合わせが大変。

Entry: ブックマーク

Entry: ブックマーク

ブックマーク

Initial post: 2009.06.06 | Last modified: 2009.06.06