アクセスログのパースはたまにしかやらないけど、忘れるので書いとこう

<?php
$fp = fopen('access_log','r');
while ($d = fgets($fp, 8192)){
  var_dump(parse_log($d));
}

function parse_log($line){
  
  if (preg_match('@^([\d\.]+) \- \- \[(.*)\] "(GET|POST|HEAD) ([^ ]+) HTTP/([^ ]+)" (.*) (.*) "(.*)" "(.*)"$@', rtrim($line), $matches)) {
    // 4xx エラーコードは処理しない
    $ip = $matches[1];
    $status = $matches[6];
    if (preg_match('@^4\d{2}$@',$status)) return;
    $parts = preg_split("@[: /]@", $matches[2]);
    $epoch = strtotime(sprintf("%d %s %d %d:%d:%d", $parts[0], $parts[1], $parts[2], $parts[3], $parts[4], $parts[5]));
    $t = strftime("%Y-%m-%d %H:%M:%S", $epoch);
    $req = $matches[4];
    $ref = $matches[8];
    $ua = $matches[9];
    return compact("ip","status","req","ref","ua","t");
  }
}

yesodを試す

ubuntu server 64bit 11.10 環境でyesodを始める

haskell-platformによると、ubutnu 11.10はhaskell-platform-2011.2.0.2がはいる。cabalは0.10.2が入った。

% sudo aptitude install haskell-platform
% sudo aptitude install libedit-dev libbsd-dev libgmp3-dev zlib1g-dev freeglut3-dev
% cabal update
// ここでコーヒータイム
% cabal install yesod

// pathを通す
% echo 'PATH=$HOME/.cabal/bin:$PATH' >> ~/.zshrc
% source ~/.zshrc

// init実行で対話モード
% yesod init
Welcome to the Yesod scaffolder.
I'm going to be creating a skeleton Yesod project for you.

What is your name? We're going to put this in the cabal and LICENSE files.

Your name: otmb
Welcome otmb.
What do you want to call your project? We'll use this for the cabal name.

Project name: yesodtest
Great, we'll be creating yesodtest today, and placing it in yesodtest.
What's going to be the name of your foundation datatype? This name must
start with a capital letter.

Foundation: Yesodtest
Yesod uses Persistent for its (you guessed it) persistence layer.
This tool will build in either SQLite or PostgreSQL or MongoDB support for you.
We recommend starting with SQLite: it has no dependencies.

We have another option: a tiny project with minimal dependencies.
Mostly this means no database and no authentication.

So, what'll it be?
s for sqlite, p for postgresql, m for mongodb, or t for tiny: m

次にプロジェクト作成

% cd yesodtest
% cabal configure -fproduction
Resolving dependencies...
Configuring yesodtest-0.0.0...
cabal: At least the following dependencies are missing:
hjsmin >=0.0.14 && <0.1,
persistent-mongoDB ==0.6.*,
yesod-default ==0.4.*,
yesod-static >=0.3.1 && <0.4

// 色々無いと怒られた
% cabal install hjsmin persistent-mongoDB  yesod-default yesod-static

// 気を取り直してconfigure
% cabal configure -fproduction
% cabal build

Herokuに登録

前回からの続き

Getting Started with Herokuを参考にherokuをinstall

// rvm インストールしてパスを通す
% sudo aptitude install curl git make
% bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)

% echo 'PATH=$HOME/.rvm/bin:$PATH' >> ~/.zshrc
% source ~/.zshrc
% rvm install 1.9.2 && rvm use 1.9.2 --default

// heroku インストール
% gem install heroku
% echo 'PATH=$HOME/.rvm/gems/ruby-1.9.2-p290/gems/heroku-2.14.0/bin:$PATH' >> ~/.zshrc
% source ~/.zshrc
% heroku version

// ここで apt-get install libopenssl-ruby とか出るがパッケージ探しても無いので下記で対応
% rvm pkg install openssl
% rvm install 1.9.2 -C --with-openssl-dir=$HOME/.rvm/usr 

ちなみにパスを$HOME/.rvm/gems/ruby-1.9.2-p290/gems/binにすると以下のエラーが出た。

/home/xxxx/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/site_ruby/1.9.1/rubygems/dependency.rb:247:in `to_specs': Could not find heroku (>= 0) amongst [minitest-1.6.0, rake-0.8.7, rdoc-2.5.8] (Gem::LoadError)

あとは、「Haskell on Heroku」を参考で完了。

IRCの部屋に在席してる人を取得してくる

PEARのライブラリの使い方がいまひとつ解らなかったので自分で書いてみた。

<?php

  $host = '192.168.100.10';
  $port = 6667;

  $irc = new irc();
  $irc->connect($host,$port);
  $irc->login('test_bot');
  $irc->read();
  $irc->send('names #testroom');
  $buffer = $irc->read();

  $row = split("\n",$buffer);
  $members = preg_replace("@^:(.*):(.*)$@",'$2',$row[0]);

  echo "<html><body><h1>IRC Login User</h1><pre>";
  foreach(split(" ",$members) as $name){
    echo $name ."\n";
  }
  echo "</pre></body></html>";

  class irc {
    function connect($host,$port,$timeout=30){
      $this->sock = fsockopen($host,$port,$errno,$errstr,$timeout);
      if (!$this->sock) echo "{$errstr} ({$errno})";
    }
    function send($cmd){
      $cmd .= "\n";
      fwrite($this->sock, $cmd);
    }
    function login($nickname, $username='user', $password = "", $realname='bot', $hostname='hoge', $servername='hoge'){
      $this->send(sprintf("USER %s %s %s %s",$username, $hostname, $servername, $realname));
      $this->send("NICK " . $nickname);
    }
    function read(){
      return fread($this->sock,4096);
    }
  }

Redmineの $git pullが遅いので。。

script/runner "Repository.fetch_changesets" -e production だと全てのプロジェクトのリポジトリを更新して遅いので、指定のプロジェクトだけを更新するようにした。

こんな感じにシェルを作成して、コードの指定がある場合は指定プロジェクトのみを更新するようにした。

  • hooks/post-update
#!/bin/sh
/usr/local/bin/post-commit.sh [プロジェクトコード]
  • post-commit.sh
#!/bin/sh

APIKEY="APIのKEY"
ID=$1

if [ $# = 0 ]; then
/usr/local/bin/ruby /var/lib/redmine/script/runner "Repository.fetch_changesets" -e production
else 
/usr/bin/wget -q -O /dev/null "https://[RedmineのURL]/sys/fetch_changesets?key=${APIKEY}&id=${ID}"
fi

Gitを使ってコンフリクトを試す

※Git version 1.7.4.1 で試しました。
資料はPro Gitを参考にまとめました。

master ブランチのみでコンフリクトしてみる

  • 同じファイルに変更がかかっているとpullは出来ない
% git pull
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From gkan:gittest
   c90d273..c3a0c18  master     -> origin/master
Updating c90d273..c3a0c18
error: The following untracked working tree files would be overwritten by merge:
        config.yml
Please move or remove them before you can merge.
Aborting
  • ローカルのリポジトリにコミットするとpullできる。pullすると勝手にmergeされる
% git commit -am 'change config.yml'
[master 0d9553e] change config.yml
 1 files changed, 2 insertions(+), 0 deletions(-)
 create mode 100644 config.yml

% git pull
Auto-merging config.yml
CONFLICT (add/add): Merge conflict in config.yml
Automatic merge failed; fix conflicts and then commit the result.

// 中身
% cat config.yml
<<<<<<< HEAD
hage
hage
=======
hoge
hoge
hoge
>>>>>>> c3a0c186114523678443d95a62c97c1b8763a503

// 修正する
% git mergetool

% git commit -am 'conflict config.yml fix'
% git push

○考察
これがsubversionの場合 $ svn update でコンフリクトするとファイルが消滅する可能性があるがcommitしているので消える心配はない。
以下はその確認。

% git show c3a0c186114523678443d95a62c97c1b8763a503:config.yml
hoge
hoge
hoge
% git show 5fde2874f852ba978e96a51c302395e842aee0c0:config.yml
hage
hage

ローカルブランチを用意してコンフリクトしてみる

  • ブランチdevを作成して、masterで変更内容を取得
% git checkout -b dev
Switched to a new branch 'dev'

// 変更してcommit
% vi config.yml
% git commit -am 'change config.yml'
[dev 1d9b4d1] change config.yml
 1 files changed, 2 insertions(+), 0 deletions(-)

// masterに切替て変更内容取得
% git checkout master
Switched to branch 'master'

% git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From gkan:gittest
   5fde287..ce03373  master     -> origin/master
Updating 5fde287..ce03373
Fast-forward
 config.yml |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
  • masterのブランチにdevの内容を反映するとコンフリクトになる
% git merge dev
Auto-merging config.yml
CONFLICT (content): Merge conflict in config.yml
Automatic merge failed; fix conflicts and then commit the result.

// conflictを修正してリモートのリポジトリに反映
% git mergetool
% git commit -am 'conflict config.yml fix'
[master 5d09e4e] conflict config.yml fix
% git push
Counting objects: 10, done.

// dev に切替
% git checkout dev
Switched to branch 'dev'

// mergeするとmasterを真として適用された
% git merge master
Updating 1d9b4d1..5d09e4e
Fast-forward
 config.yml |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

○考察
本番サイトはreleaseタグを切って運用となるが、リリースブランチを開発者以外が直接触ることから、ローカルブランチを分けて変更内容をmasterに反映とする

リリースブランチの作成と切替

  • ローカル
// リリースブランチ作成して、新しいブランチに切替
% git checkout -b iss1

% git commit -am 'release iss1' 

% git push origin iss1
  • 本番環境
// リモートリポジトリ取得
% git fetch

// リモートリポジトリ確認
% git branch -r
  origin/HEAD -> origin/master
  origin/iss1
  origin/master

% git checkout --track origin/iss1

% git branch
* iss1
  master
  • 不要になったリモートブランチを削除(※利用には注意)
% git push origin :iss1

PhoneGapについてまとめてないまとめ

下記はプレゼンネタ用にまとまっていないことをとりとめなく書いた内容ですのであしからず。

PhoneGapとはなにか?

クロスプラットフォーム・モバイルアプリケーションの開発フレームワーク
HTML5CSSJavaScriptで開発できる

PhoneGapとTitanium Mobileと比較してみた

PhoneGap Titanium Mobile
メモリ管理 出来ない 出来ない
デプロイ 速い 遅い
パッケージ容量 10M 120〜150M
ライセンス MIT or BSD Apache v2
v1.0 2011.7.28 2010.05
開発言語 HTML5CSSJavaScript Javascript
アプリ容量 - 大きい

デプロイの速度に差があるのはPhoneGapはWebViewベースなのと、Titanium Mobileはネイティブなコードに変換しているからとのこと。PhoneGapはネイティブなコードとコンパイル速度変わらない感じ。
もちろんデプロイには正確な数字や環境が異なったのもあるけど、XcodeでのiPhoneアプリコンパイルにPhoneGap1秒(Core i5 1.6GHz)、Titanium Mobile 30秒(Core2 Duo 2GHz)


Titanium Mobileのアプリの容量が大きくなるのは元から含まれるライブラリ群が多い為。
最小サイズ(Hello World)で3Mくらいになったかと。
ちなみに少し前に作ったアプリ CheerDogsは600KB程度でした。


これもうろ覚えだけど、Titanium MobileはiPhone由来のボタンとか使用できたはず。
PhoneGapは自分で用意する必要がある。

PhoneGapで出来ること

http://www.phonegap.com/about/features

対応OSの種類が多い。WIndows Phone7は対応してないみたい。
JavaScriptから位置情報、カメラ、ストレージにアクセス出来るのがよいかなと。

実績

PhoneGapを使ったアプリを iPhone AppStore、Android Marketにリリース出来た人多数。

まとめになっているか解らないまとめ

web系の開発者、デザイナーでもアプリを作れそう。リリースできそう。
環境構築も簡単。ただし、Androidのデプロイが普通に遅い環境の人は開発手法は考えた方がよさそう。
WEBサービスもアプリストアにないと利用してもらえない状況も出てるので実績作るにはよいかなと。
アプリなのにアプリに縛られてない感じ。アプリをよく知らない人がアプリ作ると、利用者は操作に戸惑いそう。
アプリのOSが増えてきてるのでクロスプラットフォーム対応で、今までの言語使えるのはとても重要かなと。
Titanium Mobileの画面遷移はOS毎に操作を変える必要がある。PhoneGapはWebViewベースなので何処まで制限が緩いのか作らないと不明。