Hatena::ブログ(Diary)

くろまほうさいきょうでんせつ RSSフィード Twitter

2012/06/01 (金)

github でサブアカウント、ユーザー切り替え


Githubでサブアカウントを使おうとしてもSSH公開鍵が同じだと同じユーザーと判断されてしまうため、そのままだとユーザー切り替えとか簡単には出来ません。

以下やりかた

メインアカウントの設定は既にできてるものとします。

まずはサブアカウントの準備

サブアカウント用のsshキーペア作成
cd
mkdir ~/.ssh/key4github/
cd ~/.ssh/key4github/
ssh-keygen -t rsa -C "hoge@example.com"

キーの場所指定で ~/.ssh/key4github/ とする
パスフレーズを忘れないように

サブアカウント用のGithub側設定

右上アイコンAccountSettings>SSH Keys>Add SSH Keys から
できた id_rsa.pub をはりつけ。

接続確認

さっき作った鍵でアクセスできるかどうか試します。

ssh -i ~/.ssh/key4github/id_rsa -T git@github.com

メインとサブの使い分け

簡単にサブアカウントアクセスできるようにSSHの設定を行います。

hoge.github.com でsshできるようにする

~/.ssh/config 編集

Host hoge.github.com
    User git
    Port 22
    Hostname github.com
    IdentityFile ~/.ssh/key4github/id_rsa
    TCPKeepAlive yes
    IdentitiesOnly yes

確認

ssh -T hoge.github.com

サブアカウント用リポジトリ作成

githubのチュートリアルどおり新repository作ってこのリポジトリ(サブアカ)用のconfigを設定する。
しかし、このままだといつものSSHキーを使ってしまうのでメインのアカウントにつなげてしまいます。

接続先をいじる

リモートの指定を先ほど.ssh/configで設定したホストにする
(gitコマンドで add remote するときに指定しちゃったほうが手っ取り早いかも)

[remote "origin"]
#   url = git@github.com:hoge/firstrepo.git
    url = git@hoge.github.com:hoge/firstrepo.git

これでgithubへの接続時にさっき作ったサブアカウントのSSHキーを使うようになり、サブアカウントでの接続となります。

おまけ

ユーザー名や(あれば)APIキーも変更。

[github]
    user = hoge
    token = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[user]
    name = hoge 
    email = hoge@example.com

ここまでだと毎回パスフレーズを聞かれるがそれはまた別件。

2012/05/21 (月)

SSHしか通らないサーバーで適当なポートに立ち上げたサービスにアクセスする


railsとかjsTestDriverとかJenkinsとか最近ではPHPのビルトインウェブサーバーもそうなんですが、コマンド一発サービス起動して後はブラウザからアクセスするだけで利用できるものがよくあります。
でも、サービスを起動したサーバーでは開けてるポートが限られてて結局使えない、とかいうこともままあります。

  ↓

ダイナミック転送SocksProxyでかいけつ!

(SSH接続にはPuTTYを使ってるものとします)

PuTTY + pfwd でダイナミック転送の設定

pfwd.iniの編集

puttyのインストールフォルダに pfwd_sample.ini ファイルがあります。
それをコピーして pfwd.ini を作成して編集。

編集を行なう部分を抜粋しました。

接続先サーバーの設定

[SSH]
; SSHサーバーアドレス
; PuTTYで保存したセッションの設定を使用する場合には@セッション名で指定します。
; 省略できません。
Host=dev.example.com

秘密鍵(.ppk)

; プライベートキーファイル (rsa, rsa2, dsa)
; ・省略時にはセッションに設定されているものが使われます
; puttygen.exeで作成(変換)したファイル
PrivateKey=C:\path\to\privatekey\hoge_dsa.ppk

ユーザー名

; ログインユーザ
; ・省略時にはセッションに設定されているものが使われます
User=calpo

ポート1080でダイナミック転送を行なう設定

;;=================================================
;; HOST4 Dynamic Forwarding
;;=================================================
01=D1080

pageant 実行

いつものようにpageantで秘密鍵を指定しておきます。

pfwd 実行

これで、pfwdがlocalhost:1080で受けて、iniで指定したホストに転送を行なうようになります。

エラーなどあった場合こちらのページが参考になりました。
http://old.typemiss.net/blog/kounoike/20061019-100

ブラウザの設定

そして肝心のブラウザの設定です。

やろうとしていること
  • ブラウザには http://development-server:8080/ みたいにして、アクセス
  • ブラウザは development-server へのアクセスを localhost:1080 に投げる

proxy.pac の作成

development-serverへのアクセスの場合のみプロキシを通すようにしたいです。
これにはスクリプトが使えます。

以下のようなファイルを作ります (名前は何でもいい)
proxy.pac

function FindProxyForURL(url, host)
{
	if (host == "development-server") {
		return "SOCKS5 127.0.0.1:1080";
	}
	return "DIRECT";
}

ブラウザの設定

プロキシの設定に先ほど用意したスクリプトを使うようにします。

  • Firefox の場合
    • ツール > オプション > 詳細 > 接続 > 接続設定
    • 自動プロキシ設定スクリプトURL にproxy.pacを指定 > 再読み込み
      • 例) file:///C:/etc/proxy.pac

f:id:calpo:20120521144323p:image:w360

  • Chrome の場合
    • スパナアイコン > 設定 > 詳細設定を表示... > ネットワーク > プロキシ設定の変更... > 接続 > LANの設定
    • 自動構成スクリプトを使用する にチェック
    • アドレス にproxy.pacを指定 > OK
      • 例) file:///C:/etc/proxy.pac

f:id:calpo:20120521144324p:image

Firefoxで問題があった場合の追加設定

名前解決で問題があった場合はこちらが参考になりました。
http://www.knonline.net/d/?date=20080611

  • アドレスバーに「about:config」と入力して開く
  • network.proxy.socks_remote_dnsの項をtrueに変更する


準備完了

あとは dev.example.com サーバーでJenkinsなり何なり立ち上げて
http://development-server:8080/ とかでアクセスしてみましょう。

参考

http://old.typemiss.net/blog/kounoike/20061019-100
http://d.hatena.ne.jp/tkng/20090621/1245539830
http://www.knonline.net/d/?date=20080611

2012/05/08 (火)

git svn switch --relocate 的なことをする (patch利用)

http://d.hatena.ne.jp/do_aki/20110530/1306751266
↑で紹介されているような .git/config を書き換える方法が使えない場合の話です。
(旧svnリポんジトリが時すでに削除済み とか)

新gitワーキングツリーに手動でブランチを移植する感じでがんばります。

全体の流れ

  • 旧gitワーキングツリーで対象ブランチのパッチ作成
  • 新gitワーキングツリーで対応するブランチ作成
  • 新gitワーキングツリーのブランチでパッチ適用

旧gitワーキングツリーで対象ブランチのパッチ作成

こんな感じの状態だとします
$ tree
.
|-- patch        #パッチ置き場
|-- new_gitrepo  #新git-svnワーキングツリー
`-- old_gitrepo  #旧git-svnワーキングツリー

旧リポジトリで移植したいブランチを確認します。

ブランチの派生元となるmasterのコミット

移植したいブランチの最新コミット
を確認。

$ cd ~/old_gitrepo
$ git log --oneline --decorate --all --graph
* d456789 (br2) 修正bar
| * c345678 (br1) 修正foo
|/
* b234567 (HEAD, git-svn, master) 修正fuga
* a123456 修正hoge
  ・・・

パッチを生成します

git format-patch 取得範囲自..取得範囲至 -o パッチ保存ディレクトリ

$ git format-patch b234567..c345678 -o ~/patches/br1
$ git format-patch b234567..d456789 -o ~/patches/br1

新gitワーキングツリーにブランチを作ってパッチ適用

ブランチ作成してパッチ適用
$ cd ~/new_gitrepo
$ git checkout -b br1
$ git apply ~/patches/br1/*
$ git ci -m "修正foo"

もう一つのブランチも同様に

masterからブランチ作る

$ git checkout master
$ git checkout -b br2
$ git apply ~/patches/br2/*
$ git ci -m "修正bar"

以上。

パッチのメッセージがメール用にエンコードされたままっぽかったので、git am とせずに apply でコミットメッセージを改めて設定しています。

というか旧ワーキングツリーのブランチの個々のコミットの情報は失われてひとまとめになっちゃいますね。

2012/04/02 (月)

「それより俺のテストを見てくれ。こいつをどう思う?」「すごく・・・日本語です・・・・」

「それより俺のテストを見てくれ。こいつをどう思う?」

f:id:calpo:20120331212922p:image:w640

「すごく・・・日本語です・・・・」


オラっち、日本語でテストメソッド名を定義するんダーーイ

PHPって、メソッド名を日本語で定義できます(文字コードUTF-8なら)。PHPでTDDワークショップで初めて知りました。
ということでテストクラスのメソッドを日本語で定義してたんですが、普通はメソッド名が日本語になってたら驚きますよね。

ということで、日本語でメソッドを定義することについて、ちょっとまとめてみます。

日本語で関数定義とかマジ勘弁☆

日本語メソッド名に対する拒否反応はおおよそ以下のような感じ。

とにかくありえない
  • ありえん
  • なにこれキモい
  • (無言で)rm -rf test/unit/*

気持ちはわかります。具体的には次のどちらか、もしくは両方になるんじゃないでしょうか。

ひらがなと漢字がありえない
  • 日本語ネイティブでない人が関わる可能性がある(可能性を無視できない)

確かにこの場合日本語はナシでしょう。(こういうケースが多いと思いますが)
ドキュメントとしてのテストコードの存在意義が潰されてしまいますからね。

自然文がありえない
  • たとえ英語でであっても "testHogeShouldBeConvertedToFugaWheneverFlagIsTrue()" みたいなのはメソッド名として受け入れられない。

あいやしばらく!
こういうケースでは "testHogeParser()"みたいなテストメソッドの中に大量のassersionが詰め込まれて、そのテストメソッドが何をテストしたいのかわかりづらくなっている場合があり、日本語にするかどうかは別としても一考の余地ありだと思っています。

でもちょっと待って、そのテストメソッドはなんのため?


テストメソッドって(別のコードから)呼び出さないよね

このメソッドを呼び出すために日本語をカタカタ打ち込んだりする必要はないです。
後から読むだけであり、あとから読むことが重要です。
通常のメソッドと違ってコードの文脈の中で目にすることはなく、見るのは定義本体のみで、通常のメソッド名に求められるような「簡潔さ」は求められません。

詳細に保証(説明)したいことがある

テストメソッドは1つの事柄をテストすべきで、メソッド名はテストで保証(説明)したい事柄を明確にするものであるべきです。
これは1つのテストメソッドにassertionを1つだけとするのが良いとされる理由の一つです。
「そのメソッドが何をテストしているのか」が重要になります。

仕様書を見るのに近い感覚で後から見ることが多い

テスト対象の仕様やインターフェースを保証するドキュメント的な役割を求めてテストケースを見ることがあります。
アウトラインからテストメソッド一覧を俯瞰する等の場合、一目で内容が頭に入ると嬉しいです。

じゃぁ日本語で書いたらよくね?

上に挙げたような理由で、テストが日本語(英語にしても自然文に近い形)で書いてあると得すると考えています。

表現しやすい&伝わりやすい

ドキュメントやWikiを日本語で書く感覚でテストメソッドを日本語で書いています。
対象処理の仕様や気を付けたい罠動作を他者に伝えたいとき、テストが意図することを表現しやすいです。

一覧時の一目で分かる感

テストメソッド一覧を出したり、テストの失敗レポートが出た時などにその効果を感じます。

*ただし

「環境が許せば」です。日本語ネイティブ以外の人が触れる可能性を無視できないなら日本語にするのは難しいでしょうし、「生理的に受け付けない」というのも無視できない理由になり得ます。
ものにもよります。「Githubで公開」的なものは全部英語でやったほうが得が多いでしょう。

まとめ

つまり日本語がどうどいうよりは

  • テストの粒度を小さく保とう
  • テストが何をテストしているのか明確にしよう

追記 2012/04/26

メソッド名に日本語を使うとエディタによってはシンタックスハイライトが正しく動作しないケースがあることが判明。(なにをいまさら)
英語派に寝返る。

2012/03/31 (土)

自分用にインストールしたpearを使おうとしてredeclareみたいに文句言われた場合

丁度ファイル入出力が絡むテストを書いて、めんどくさいなー、と思っていたところに
http://blog.yuyat.jp/archives/1280
↑でvfsStreamというものが紹介されていたので試そうとしたらひっかかったのでメモ。

とりあえずCache_Casualのテストを実行してみる

tests/unit/bootstrap.phpに自分用pearのインクルードパスを追加。

<?php
set_include_path('/home/calpo/share/pear/php' . PATH_SEPARATOR . get_include_path());

$ phpunit --bootstrap bootstrap.php Cache/Casual/Container/FileTest.php

PHP Fatal error:  Cannot redeclare class File_Iterator in /home/calpo/share/pear/php/File/Iterator.php on line 196
Fatal error: Cannot redeclare class File_Iterator in /home/calpo/share/pear/php/File/Iterator.php on line 196

自分用のpearディレクトリは後ろに設定する

<?php
// ×
set_include_path('/home/calpo/share/pear/php' . PATH_SEPARATOR . get_include_path());

// ○
set_include_path(get_include_path() . PATH_SEPARATOR . '/home/calpo/share/pear/php');

実行できるようになった。

$ phpunit --bootstrap bootstrap.php Cache/Casual/Container/FileTest.php
PHPUnit 3.5.3 by Sebastian Bergmann.
..
Time: 0 seconds, Memory: 5.25Mb
OK (2 tests, 2 assertions)

2011/12/10 (土)

PyrusでプロジェクトローカルなPEARライブラリインストール : PHP Advent Calendar jp 2011 Day 10


PHP Avent Calendar jp 2011の10日目、@です。
→前日「includeとextractの組み合わせでテンプレート処理を作る。PHPのAdvent Calender #9 - ブックマクロ開発に

みなさんPEAR使ってますか?

PEARのライブラリを普通にインストールすると/usr/binとかに入るんですが、そうじゃなくて自分用に~/binに入れたいとか、フレームワークのvendorディレクトリに入れたいとかありますよね。
これで結構苦労していたところ、今年のPHPカンファレンスで「Pyrus使うと捗るよ」みたいな話を聞きくことができました。
pearの後継となるパッケージマネージャらしく、「なにそれすごい!これでかつる!」と期待に胸をふくらませつつ家に帰って試してみたところ・・・

とにかく日本語の情報が全然無い

という状態でなんか凹みました。

でも、Pyrusだとpearよりもプロジェクトローカルなライブラリのインストールがやりやすいです!
ということでPyrusによるPEARライブラリインストールのご紹介。

まずは俺ローカルなPEARライブラリインストール

~/mypyrusに自分用のPEARライブラリをインストールしてみます。
(必ずしも俺ローカルが必要なわけではないですが、整理しやすかったのでこのようにしています)

pyrus.pharダウンロード

pyrus.phar自体はどこにあってもいいんですが、とりあえず~/mypyrusに入れておくことに。

$ mkdir mypyrus
$ cd mypyrus/
$ wget http://pear2.php.net/pyrus.phar

pyrusの初期設定

最初にpyrusを実行すると初期設定が行われ、パッケージのインストール先のディレクトリ等が設定されます。

$ php pyrus.phar install
Pyrus version 2.0.0a3 SHA-1: BE7EA9D171AE3873F1BBAF692EEE9165BB14BD5D
Pyrus: No user configuration file detected
It appears you have not used Pyrus before, welcome!  Initialize install?
Please choose:
  yes
  no
[yes] :
# ↑yesなのでそのままEnter
Great.  We will store your configuration in:
  /home/calpo/.pear/pearconfig.xml
Where would you like to install packages by default?
[/home/calpo/mypyrus] :
# ↑にインストールなのでそのままEnter

$ ls ~/.pear/pearconfig.xml
/home/calpo/.pear/pearconfig.xml

~/.pear/pearconfig.xmlが作成されます。

config-showコマンドで設定を確認できます。

$ php pyrus.phar config-show
Pyrus version 2.0.0a3 SHA-1: BE7EA9D171AE3873F1BBAF692EEE9165BB14BD5D
Using PEAR installation found at /home/calpo/mypyrus
System paths:
  php_dir => /home/calpo/mypyrus/php
  ext_dir => /usr/lib64/php/modules
  cfg_dir => /home/calpo/mypyrus/cfg
  doc_dir => /home/calpo/mypyrus/docs
  bin_dir => /usr/bin
  data_dir => /home/calpo/mypyrus/data
  ・
  ・

bin_dirが/usr/binになっているので自分用に変更しましょう。
(~/mypyrus/.config が生成されます)

$ php pyrus.phar set bin_dir /home/calpo/mypyrus/bin
$ php pyrus.phar config-show
  ・
  ・
  bin_dir => /home/calpo/mypyrus/bin
  ・
  ・

PHPUnitインストール

準備ができたので俺専用PHPUnitをインストールしてみましょう。

$ php pyrus.phar set auto_discover on
$ php pyrus.phar channel-discover pear.phpunit.de
$ php pyrus.phar install phpunit/PHPUnit
Pyrus version 2.0.0a3 SHA-1: BE7EA9D171AE3873F1BBAF692EEE9165BB14BD5D
Using PEAR installation found at /home/calpo/mypyrus
Sorry, phpunit/PHPUnit references an unknown channel pear.symfony-project.com for pear.symfony-project.com/YAML
Do you want to add this channel and continue?
Please choose:
  yes
  no
[yes] :
# ↑途中チャンネルの追加について問われます
  ・
  ・
pear.phpunit.de/PHP_Invoker depended on by pear.phpunit.de/PHPUnit

どん!
入りました。

$cd ~/mypyrus
$ ls
bin  cache  docs  downloads  php  pyrus.phar

$ ls bin/
phpunit

$ ls php/
File  PHP  PHPUnit  SymfonyComponents  Text


include_pathの設定

早速bin/に入ったphpunitを実行しようとしても、必要なディレクトリがinclude_pathに設定されていないので怒られます。

$ cd ~/mypyrus/bin
$ ./phpunit
Warning: require(PHPUnit/Autoload.php): failed to open stream: No such file or directory in /home/calpo/mypyrus/bin/phpunit on line 42

$ php -i | grep include_path
include_path => .:/usr/share/pear:/usr/share/php => .:/usr/share/pear:/usr/share/php

今回はお手軽に~/mypyrus/bin/phpunit に設定を追加して、~/mypyrus/phpをinclude_pathに入れてしまいます。

// ↓をrequireの前に追加
set_include_path(
	realpath(dirname(__FILE__).'/../php')
	. PATH_SEPARATOR . dirname(__FILE__)
	. PATH_SEPARATOR . get_include_path());

ただライブラリによってbin/に入るファイルがphpスクリプトだったりシェルスクリプトだったり、PHP_CLASSPATHみたいな独自の環境変数を設定する必要があったりとなんかもう・・・
php.iniが変更できるならそれが一番確実です。

$ cd ~/mypyrus/bin
$ ./phpunit --version
PHPUnit 3.6.4 by Sebastian Bergmann.

いぇーい

プロジェクトローカルなPEARライブラリインストール

続いて適当なプロジェクトのvendorディレクトリにプロジェクト専用PEARライブラリをインストールしてみます。

ディレクトリの設定

setとかのコマンドの前にディレクトリを指定してあげると、そこローカルな作業と設定ができます。
(そのディレクトリに.configが出来上がります)

例えば~/project_hoge/vendorにインストールする場合・・・

$ php pyrus.phar /home/calpo/project_hoge/vendor set bin_dir /home/calpo/project_hoge/vendor/bin
$ php pyrus.phar /home/calpo/project_hoge/vendor config-show
Pyrus version 2.0.0a3 SHA-1: BE7EA9D171AE3873F1BBAF692EEE9165BB14BD5D
Using PEAR installation found at /home/calpo/project_hoge/vendor
System paths:
  php_dir => /home/calpo/project_hoge/vendor/php
  ext_dir => /usr/lib64/php/modules
  cfg_dir => /home/calpo/project_hoge/vendor/cfg
  doc_dir => /home/calpo/project_hoge/vendor/docs
  bin_dir => /home/calpo/project_hoge/vendor/bin
  ・
  ・

インストール

チャンネルの設定などもプロジェクトローカルなのでまた設定します。

$ php pyrus.phar /home/calpo/project_hoge/vendor set auto_discover on
$ php pyrus.phar /home/calpo/project_hoge/vendor channel-discover pear.phpunit.de
$ php pyrus.phar /home/calpo/project_hoge/vendor install phpunit/PHPUnit
  ・
  ・
pear.phpunit.de/PHP_Invoker depended on by pear.phpunit.de/PHPUnit

$ ls ~/project_hoge/vendor/bin
phpunit

こんな感じでプロジェクトローカルなPEARライブラリをほいほいインストールしていけます。

さらに・・・

package.xmlをmakeしてプロジェクトごとに必要なパッケージをまとめて管理したりと夢がひろがるらしいので日本語の情報ください :)

みんなでつかおうPyrus!


明日は@さんです。

2011/11/04 (金)

session_set_save_handler()でカスタムセッションハンドラ設定したらFatal error: Class not found


複数のwebサーバーでセッション情報共有するのにmemcached使うためにカスタムセッションハンドラ設定したら
ばっちり定義してるはずのクラスがなかったことになっててびびった話。

問題のあったスクリプト

  • クラスHogeを定義
  • writeハンドラでnew Hoge()
class Hoge {}
class MySessionHandler {
    public function open($save_path, $session_name){ /*処理*/ }
    public function close(){ /*処理*/ }
    public function read($id){ /*処理*/ }
    public function write($id, $sess_data){
        $hoge = new Hoge();
    }
    public function destroy($id){ /*処理*/ }
    public function gc($maxlifetime){ /*処理*/ }
}

$s = new MySessionHandler();
session_set_save_handler(array($s,'open'), array($s,'close'),
	array($s,'read'), array($s,'write'), array($s,'destroy'), array($s,'gc'));

session_start();
$_SESSION['fuga'] = 'abc';

↓ごらんの有様だよ!

Fatal error: Class 'Hoge' not found in /xxx/xxx/sessiontest.php on line 8

Hogeってすぐそこに定義してるじゃん! Σ(・ω・;)

エラーの原因

どこでエラーになってるか

session_set_save_handler()の引数(callback $write)で指定した処理の実行時にエラーが起きています。

なんでエラーになってるか

http://php.mirror.camelnetwork.com/manual/ja/function.session-set-save-handler.php#refsect1-function.session-set-save-handler-notes

PHP 5.0.5 以降、write ハンドラおよび close ハンドラはオブジェクトが破棄されたあとにコールされます。 そのため、セッション内でデストラクタを使用可能ですが、 ハンドラ内ではオブジェクトを使用できません。

オブジェクトが破棄されて、定義されていたクラスやインスタンスがなかったことになっています。
(requireの状態は残ってるようで、require_onceしても対象のクラスファイルが再度読み込まれたりはしない)

解決方法

デストラクタでsession_write_close()

オブジェクト破棄の前にwriteハンドラコールすればよい。
http://php.mirror.camelnetwork.com/manual/ja/function.session-set-save-handler.php#refsect1-function.session-set-save-handler-notes

この「ニワトリが先かタマゴが先か」の問題を解決するために、 デストラクタから session_write_close() を コールすることが可能です。


こんな感じでOK
<?php
class MySessionHandler {
	// 省略 //

	// ↓追加
	public function __destruct(){
		session_write_close();
	}
}