その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

Maven Archetype で文字列を置換したりする

Maven Archetypearchetype を作るとき,文字列を置換したくなることがあります.
例えば $artifactIdfoo-bar と入っている時にこれを foo_bar という風に s/-/_/g したくなる事などがあるでしょう.世の中色々あるのです.

そういう時は以下のように書いてやると良い.

${artifactId.replaceAll("-", "_")}

こういう感じで普通に replaceAll() 等の String のインスタンスメソッドを呼び出すことが出来るので便利.


でもって pom.xml

#set($replaced = $artifactId.replaceAll("-", "_"))

とか書いてやると,archetype 内で $replaced という変数が置換後の内容として使えるようになるので便利!!


現場からは以上です.

Maven Archetype で ## がコメントとして扱われるのでなんとかする

Maven Archetypearchetype を作る時,archetype に含めるファイルの中に ## が入っていると行のそれ以降がコメントとして扱われる為,内容が抜け落ちてしまうというような事があります.
例えば Markdown 形式のファイルなんかを archetype 内に含めていると悲惨で,

## My Awesome Project!

という風に,見出しを期待して ## から始める文を書いてしまうと,これはコメントとして扱われ空行として出力されることになります.
これはMaven Archetype が内部で使っている Apache Velocity が ## をコメントとして扱う為です.ジーザス.


こうした時にどうやって archetype 中のファイルで ## を使うのか,という話ですけれども,archetype-resources/pom.xml の先頭に #set($sharp = '#') と書いてやるとよろしい.


例;

#set($sharp = '#')
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
...
</project>

こうすると,$sharp という変数が # として扱われるようになります.
そして ## が含まれるファイルはこのように書き換える;

${sharp}${sharp} My Awesome Project!


見た目は悪いがコイツは動く.

YAPC::Europe 2015 にて “Static Code Analysis For Perl” というタイトルで発表します

2015年9月2日から4日までスペインはグラナダで開催される YAPC::Europe 2015 にて,
“Static Code Analysis For Perl” というタイトルで発表することになりました.実は通ると思ってなかった!!


YAPC::Europe 2015 | Static Code Analysis For Perl


例にもよって Perl の静的解析の話とか,ぶっちゃけ Perl::Lint の話になると思います.Perl::Lint はそろそろ完成の目処が立ってきているので…… *1
海外のカンファレンスで英語で話すのは一昨年のウィーン以来なので緊張しますね!


成田からの所要時間はおおよそ15時間とのことで,なんと1日かかりません.お手軽ですね.
皆さん是非現地でお会いしましょう.


ところで YAPC::Europe 2015 のトーク応募はまだ受付中のようなので,どんどん応募されると良いのでは無いかと思います.

*1:要出典

相手の GitHub の ID さえ知っていれば暗号化したメッセージを送れる naisho というのを作った

色々な事情があり,秘密のメッセージを送り合う必要性が今年に入ってから多数発生していて,
そのたびに毎度毎度手で暗号化して〜みたいな風にやるのめんどいですね,そうですね,
ということでこの度 naisho というものをこさえました.みんなには内緒ですよ.


これは何かと言うと,やりとりしたい相手の GitHub の ID を指定するだけで

  • その ID のユーザの ssh-rsa の公開鍵を引っ張ってきて
  • その ID のユーザのメールアドレスを引っ張ってきて
  • そのメールアドレスに対して公開鍵で暗号化したメッセージを添付ファイルにしてメールで送りつける

という動きをするコマンドです.
golang で書きたかったというのと golang で書くと便利なのではと思ったので golang で書いてあります.


Wercker で Go のプロジェクトをクロスコンパイルし、GitHub にリリースする - 詩と創作・思索のひろばや,
werckerでgithubにreleaseをdeployするまでの道のり - yuukichiの日記
を参考にすることで、wercker でバイナリをビルドして GitHub Releases に成果物を設置するということも出来ました.
Releases · moznion/naisho · GitHub からお手軽に入手頂けます.


さて使い方としては

$ naisho <Target GitHub ID> <Message>

としてやるだけで,対象の GitHub ID のユーザーに暗号化した Message を添付ファイルにしてメールで送りつける事ができます.
受け取った側は openssl さえ持っていれば良くて,

$ openssl rsautl -decrypt -inkey <Your Secret Key> -in <Attachment>

という感じで,公開鍵と対応している秘密鍵と添付ファイルを指定してやるだけで内容を読むことが出来ます.


中身の仕組みですが,GitHubhttps://github.com/<user-id>.key という所にアクセスすると,
任意のユーザの ssh-rsa 公開鍵の一覧を引っ張ってこれるという機能があるので *1
ここから一番上の公開鍵を引っ張ってきてそれで暗号化しています.
送信先メールアドレスはプロフィールページ (つまりhttps://github.com/<user-id>) に書いてあるメールアドレスを
GitHub API 経由で取得してくることができるのでそれで取ってきています.
従って,当然ですが公開鍵を登録していないユーザや,メールアドレスを公開していないユーザには送ることが出来ません.残念!


使う鍵の鍵長によって暗号化出来るバイト数が変わってきて,

鍵長ビット 暗号化可能バイト
1024bit 117byte
2048bit 246byte
4096bit 502byte
8192bit 1018byte

という感じなので,そこまで長いメッセージは送れないという世界観です (バイト数が溢れると暗号化に際してエラーが出る).

しかしこれは十分な長さです! これで私にクレジットカードの番号や WebMoney のコード等を安全に送り放題ですね!! やりました!!!


今後の予定としてはファイル入力を受け付けられたり,使う公開鍵をインタラクティブに選べたりできたら良いなあとぼんやり思っています.あとエラーメッセージが雑極まりないので直したいですね!
ご利用くださいませ.

*1:ゆくゆくは無くなるらしい……

git でファイルごとのコミット数を取ってきて,プロジェクト中のホットなファイルを割り出すという試み

途中の段階でプロジェクトに入った時などに,「どれがそのプロジェクトの中心となっているファイルなんだろうか」というのを手っ取り早く知りたくなる時があります.僕はあります.


そこで「どのファイルが盛んに変更されているのか」という点を指標として注目すると,良い感じにそこら辺取れるのでは無いかと思って試してみました.
コミット数が多いファイルは多く変更を加えられているということから,そうしたファイルはホットであるということが言えそうな気がしたので,git でファイルごとのコミット数を取ってきて,それをソートして見てやれば良いよな,という意識でやっていきました.もちろんコミットの粒度などもあるでしょうから一概にはそうとは言い切れませんが,参考にはなる気はします.


使うスクリプトは至って簡単.以下の様な感じです.

git ls-files |
while read file ; do
  commits=`git log --oneline -- $file | wc -l`;
  echo "$commits - $file";
done | sort -n

git で管理されているディレクトリ内でこのシェルスクリプトを走らせるとそのような情報を取ってくることが出来ます.
railsリポジトリで試してみました所,以下の様な結果が得られました.

1 - actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb
1 - actionmailer/test/fixtures/anonymous/welcome.erb
1 - actionmailer/test/fixtures/another.path/base_mailer/welcome.erb
1 - actionmailer/test/fixtures/asset_host_mailer/email_with_asset.html.erb
1 - actionmailer/test/fixtures/asset_mailer/welcome.html.erb
<中略>
549 - activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
556 - actionpack/CHANGELOG.md
745 - activerecord/lib/active_record/associations.rb
1134 - activerecord/CHANGELOG.md
1145 - activerecord/lib/active_record/base.rb

なるほどという感じです.正しいのかどうかはよくわかりません.rails 識者の方どうでしょうか.
めっちゃコミット数あった (5万コミットくらい) ので実行に15分くらいかかって大変微妙な心境になります.


よくわからなかったので,なんとなくわかるであろう Plackリポジトリで試してみます.

1 - eg/dot-psgi/Dumper.psgi
1 - eg/dot-psgi/echo-stream-sync.psgi
1 - eg/dot-psgi/runnable.psgi
1 - eg/dot-psgi/static/index.html
1 - eg/dot-psgi/static/test.js
<中略>
113 - Makefile.PL
150 - lib/Plack/Response.pm
178 - Changes
197 - lib/Plack.pm
211 - lib/Plack/Request.pm

なるほど,それっぽい感じがしますね!! (こっちはすぐ実行し終わった)


という感じでまあまあ参考になる情報が取れるのではないでしょうか,という気持ちです.試しに色々なリポジトリに適用していってますが,それっぽい結果が得られてて面白いですね.
逆にコミット数が少ないファイルはメンテされてないから危険,みたいなのも分かるんでしょうか.要検討という感じです.
グラフ等で可視化してやるとまた面白さが出てくるかもしれませんね.

参考


[追記]
歴史が深いリポジトリでやるとめちゃめちゃ時間がかかって大変なので,トラックする log の数を制限するとかが必要になってくるかもわかりませんね.
あと「昔はホットだったけど最近はホットではない」みたいなのもあると思うので,常にすべてのコミット履歴を追う必要は無くて,ある一定のところでバチッと切ってしまうとか,そういうのも考えていく必要があるのかな~とか思った次第です.

こんな風に (この例では -1000 で制限をかけている).

git ls-files |
while read file ; do
  commits=`git log -1000 --oneline -- $file | wc -l`;
  echo "$commits - $file";
done | sort -n

[追記]
log の数に制限かけても処理時間そんな変わらないので,ファイル数の問題であることが伺えます.厳しい……
とは言え「昔はホットだったけど最近はホットではない」みたいなのには関係してきそうなので検討する価値はありそう.

間違っているので見なかったことにしましょう

Groovy 所感

開発のサポートツールやらなにやらで,こまごましたものを Groovy でちょいちょい書いて思ったことです.
Groovy で Web アプリケーションを書いたとかそういうゴツい話ではないのでそのあたりはよくわかりません.
なお本記事中に出てくる Java っていうのは Java 8 以降のことを指していると思ってください.

所感
  • 楽にコードが書けるという点では良い.言語的にそういうところを重視している気がする.
    • defとか.あとは DB 操作とか結構良い.楽.
    • System.out.println() とか書かなくて良いのは本当に良いですね.
    • とは言え,なんだかんだで補完の支援を受けないと記述コストは大きいと思う.賢い補完が要る.
  • gradle は pom.xml 書くよりもストレスが小さい気がする.
    • とは言え maven でもめんどいことは gradle でもめんどい印象.
    • 結局なんか,適宜やっていきましょうという感じになる.
    • つうか gradle はあんまモリモリやってないからよくわからん!
  • 実行速度は特に感想無いです.チョイノリみたいなツールだと全く問題にならない.
    • 重い処理するやつとか,Web アプリケーションとかだと色々あるかも.知らない.
  • 書いたら LL 感覚ですぐ動くので,挙動を確認するための書き捨てのコードとかにはうってつけだと思う.フットワークが軽い.
  • groovysh 便利.Groovy の REPL 的なやつ.挙動をパッと調べたいときに有益.
  • Java と比較した時にコードが簡潔に書ける傾向にあるので,本質的な処理を理解しやすい.
    • サンプルコードとかに向いてると思う.
  • Groovy の便利記法結構あるけど,Java に似たようなのがちょいちょい入ってるから (lambda とか),そこがマッシブな優位点になるかどうかという点.
    • まあ Groovy の便利記法は便利は便利.
    • Java でも8以降は戦えるのでは.
  • 当たり前の話だが groovy の処理系が別途必要となってくる.
    • Groovy のスクリプトJava のプロジェクトの支援ツールとして配布するとなると,その利用者にGroovy のインストールを強制することになる.
    • まあ入れれば良いですねという感じだけど,めんどいですよね.
    • Java のプロジェクトの開発支援ツールに Groovy を含めるのはまま便利だ (った) と思うんですが,21世紀にはなんと CI ツールなどが存在していて,CI 回すたびに jar をパッケージできる感じになってきているので,Groovy のスクリプトではなくその jar を配布すれば良いのではという意識の高まり.
      • 新たに処理系を入れる手間とか心理的なアレとかが消える.
      • そういう jar のパッケージングが極めてめんどい時は Groovy 使うと良いのではという気持ち.
      • ブックマークコメントで便利情報もらったので追記しました.
  • Pivotal がスポンサーから外れるの心配ですね.
まとめ
  • 挙動を確認したりするための書き捨てのスクリプトに使うのは良さそう
    • ついでに言うと groovysh が便利
  • サンプルコードに使うのは向いていると思う
  • それ以外の用途で積極的に使う理由が積極的に無い……
  • Java のプロジェクトの開発支援ツールみたいな用途だったら,Groovy じゃなくて (fat-packed) jar を配ってやっていく方が良いのではないか


という感じです.こういう意識になりました.書き味は気持ちのよい部類だと思われます.
gradle はちょっと評価できるほど使っていないので感想変わるかもしれないですね.


[追記]

Groovy 所感 - その手の平は尻もつかめるさ

Groovyのインストールを強要するのでなく、groovy-all.jarをクラスパスに含めるだけで良いのでは?

2015/01/28 22:12

なるほど.良さそう.ありがとうございます.


[追記]
Java のプロジェクトに Groovy のプログラムを含めるの,まあ自分は良いんですけど他の人にも Groovy の読み書きを強いる事になるので,そのへんはどうなんでしょうね.学習コストが上がるというか,些細なことでもお作法を覚えなきゃ駄目なのは面倒臭いのではと思ってしまう.で,結局 Groovy 読み書きできる人が永劫そのあたりを面倒見る,みたいな事になったら地獄っぽい.まあ普通に Java 読み書きできたら Groovy も読み書きできそうですけども.はい.


[追記]
別の処理系 (つまり今回の場合 Groovy) に依存すると,気を配る対象 (処理系の動向追ったりとか) が増えるためにコストが高まるという見方もあるので,そのコストを Groovy のメリットでうまく相殺できるのかどうか考えていく必要がある (Java も8とかはまあまあ書き心地が軽いのでそこが支配的なメリットになるかどうか.直接実行できるというのも,配布時にコンパイルしたパッケージを置くスタイルと比較した時にどうか.まあトライアルアンドエラーや修正は楽だけれど).
依存が少なければ少ないほどメンテコストは低くなる傾向があるので,依存はバチバチ減らしたい.結局、ソフトウェアのライフサイクルを考えるとメンテフェーズが一番長くなるはずなので,そこでコストがかかるようになるとリソースをどんどん奪われてしまう.総じたコストを低く保つにはなんやかんやで単一の言語でやっていった方が良いのではないかという立場です.
我々はどうすべきか.

CUDA で 2 枚以上の GPU を使って cufft する時は FFT Plan を各々の device に乗せる必要がある

以下は間違い.

cudaSetDevice(devices[0]);
cufftHandle fft_plan;
cufftPlan1d(fft_plan, SIZE, CUFFT_C2C, BATCH); // ここで作られる FFT Plan は device 0 にしか確保されない

cufftComplex *ffted_data[2], *orig_data[2];
cudaSetDevice(devices[0]);
cudaMalloc((void **)&orig_data[0], SIZE);
cudaMalloc((void **)&ffted_data[0], SIZE);
cudaSetDevice(devices[1]);
cudaMalloc((void **)&orig_data[1], SIZE);
cudaMalloc((void **)&ffted_data[1], SIZE);

cudaSetDevice(devices[0]);
cufftExecC2C(fft_plan, ffted_data[0], orig_data[0], CUFFT_FORWARD);
cudaSetDevice(devices[1]);
cufftExecC2C(fft_plan, ffted_data[1], orig_data[1], CUFFT_FORWARD); // ここ (device 1 上) で使っている fft_plan は device 0 にしか乗っていないのでマズい

この場合,fft_plan が device 0 にだけ乗っている為,device 1 で FFT を走らせようとすると変な結果が得られる.
エラーではなく変な結果が得られる!!!!
つらい!!!!!!!!!!!
原因がわかりにくい!!!!!!
あああああああああああああああああああああああああああああああああああああああああああああ!!!!!!


正しくは以下のように,FFT を実行する各々の device 上で FFT Plan を確保しなければならない.

/*
 * ここで各 device 上で FFT Plan を確保する
 */
cufftHandle fft_plan[2];
cudaSetDevice(devices[0]);
cufftPlan1d(fft_plan[0], SIZE, CUFFT_C2C, BATCH);
cudaSetDevice(devices[1]);
cufftPlan1d(fft_plan[1], SIZE, CUFFT_C2C, BATCH);

cufftComplex *ffted_data[2], *orig_data[2];
cudaSetDevice(devices[0]);
cudaMalloc((void **)&orig_data[0], SIZE);
cudaMalloc((void **)&ffted_data[0], SIZE);
cudaSetDevice(devices[1]);
cudaMalloc((void **)&orig_data[1], SIZE);
cudaMalloc((void **)&ffted_data[1], SIZE);

/*
 * 各 device に応じて使用する FFT Plan を差し替える
 */
cudaSetDevice(devices[0]);
cufftExecC2C(fft_plan[0], ffted_data[0], orig_data[0], CUFFT_FORWARD);
cudaSetDevice(devices[1]);
cufftExecC2C(fft_plan[1], ffted_data[1], orig_data[1], CUFFT_FORWARD);

こうするとちゃんと動く.ハマった……

あああああああああああああつらい!!!!!!!!!!!!!!! 勘弁してれ!!!!!!!!!!!!!