2013年12月

「BrewfileでHomebrewパッケージを管理する」をやってみた

2014/08/04 追記: brew bundle は非推奨になりました下のほうに「辛み」について書いていますがそのあたりの問題です。シェルスクリプトで set -e すれば代わりになるでしょう。



ついさっき @deeeet さんが書いていた BrewfileでHomebrewパッケージを管理する の記事が twitter のタイムラインに流れて来たのを見つけたので、これは良いかも!と思って自分もやってみたメモ。

まずは @deeeet さんの記事をみたほうが良いのだけど、例えばこんなかんじの Brewfile というものを用意して、その Brewfile のあるディレクトリで

$ brew bundle

とすると Brewfile に記述しておいた homebrew パッケージをまとめてインストールできるというもの。

で、知らなかったのだけど、さらに homebrew-cask というものを使う事で、 homebrew 本体では管理されていないような dmg なアプリケーションのインストールもできるという便利情報ありがたい。

で、ちょっと調べてみた

1. brewdler ってあった気がするんだけど brew bundle ってデフォ?

brewdler のページに

Note: this is now a native feature in homebrew:

って書いてあった。デフォだった。すごい、よし使おう。

2. brew tap foo/bar 2回目がエラーになって失敗する

Brewfile に

tap phinze/homebrew-cask 

と書いておくと、brew bundle 2回目の実行で必ず

Error: Already Tapped!

と表示されて失敗し、処理が止まってしまう。どう回避するのが正しいのかよくわからないので、とりあえず

tap phinze/homebrew-cask || true

としたら誤摩化せたのでそうしてみた。#けど良いのかコレ‎(´・ω・`)

ちなみに、

install zsh

とかだと

Warning: zsh-5.0.4 already installed

のように Warning なので処理は続行される。brew tap も Error じゃなくて Warning にするべきなのでは??

(追記) Issue あげたら賛同してくれる人もいたのでプルリク送りました => Warning にする変更が master にはいりました :D


3. 使いたいアプリの cask がない場合はどうすれば?

phinze/homebrew-cask の Casks ディレクトリにないアプリをインストールしたい場合はどれすれば良いのだろう?と思って調べてみた。

ryurock さんが Qiita に書いてた みんなhomebrew-caskって知ってるか? の 記事にヒントが書いてあったのだけど、どうやら自分で homebrew フォーミュラのレポジトリを用意すれば良いっぽい。 ryurock さんの記事だと、homebrew-cask を fork していじろう、と書いてあったけど、自分専用の homebrew-mycask とかにしたほうが良いと思ったので、そうしてみた。

https://github.com/sonots/homebrew-mycask

Casks ディレクトリを作って他のを真似して試しに echofon.rb を書いてみた。こんなかんじ。

class Echofon < Cask
  url 'http://www.echofon.com/bin/Echofon_1.8.0.dmg'
  homepage 'http://www.echofon.com/twitter/mac/'
  version '1.8.0'
  sha1 'e02251fc05847df223295f364b5a004019d47f7b'
  link 'Echofon.app'
end

ちなみに sha1 は

openssl sha1 ファイル名

とかやれば取得できる。これで、

brew tap sonots/mycask
brew cask install echofon

でインストールできるようになったので、Brewfile に

tap sonots/mycask
cask install echofon

と書いて完成。

なお、homebrew フォーミュラのレポジトリ書いたことがなかったけれど homebrew-フォーミュラレポジトリ名 というレポジトリ名にして github に作っておくと、brew tap ユーザ名/フォーミュラレポジトリ名 で tap できるようになるっぽい。

(追記) 4. brew install foo で古いバージョンが入っている場合エラーになって失敗する

Brewfile に

install zsh

と書いていて、最新が 5.0.4 だけれどもすでに古いバージョンが入っているような場合

Error: zsh-5.0.0 already installed
To install this version, first `brew unlink zsh'

のように Error となり、処理が止まってしまう。最新 5.0.4 が入っている場合は、

Warning: zsh-5.0.4 already installed

のように Warning レベルなので問題ない。

またか。。。腐ってるな。。。と思ってプルリク を送ったけれども、下位互換性を変えたくないと言われてしまったので、今のところは

install zsh || true

のようにする感じです。うぅ辛い T T

ちなみに brew upgrade でなんとかならないかとも試したけれど、brew upgrade はインストール済みでないとエラーと出すのと、最新バージョンがすでに入っている時の挙動が brew install と違って Warning ではなく Error なので(こっちもか。。。)、結局こんなかんじになってあんまり意味がない。
install zsh || brew upgrade zsh || true
うぅ辛い T T

下位互換性も大事だけど、Brewfile サポートしたのに、こういう挙動になるのは仕様としてちょっとあんまりな気がするので、全体的に見直して欲しい。brew コマンドの挙動を変えるというよりは、Brewfile 側の処理を整えていくのが良いんだろうな。


以上、@sonots でした。
 

ruby で多重ループを抜ける3つの方法を速度比較してみた

ruby で多重ループから抜けるには、シンプルにフラグを用意して if で break する方法と、throw, raise を利用する方法がある(もっとあったら教えてください)。その3つの方法の速度比較をしてみた。

ruby 2.0.0p247 (2013-06-27 revision 41674)

require 'benchmark'
n = 1000000

foo = nil
Benchmark.bm(7, ">throw", ">raise:", ">break:") do |x|
  a = x.report("throw") { n.times {
    catch(:foo) do
      while true
        while true
          throw :foo if foo.nil?
        end
      e
    end
  }}
  b = x.report("raise") { n.times {
    begin
      while true
        while true
          raise :foo if foo.nil?
        end
      end
    rescue
    end
  }}
  c = x.report("break") { n.times {
    is_break = false
    while true
      while true
        is_break = true and break if foo.nil?
      end
      break if is_break
    end
  }}
end

結果は以下のようになった。

              user     system      total        real
throw     0.660000   0.000000   0.660000 (  0.664681)
raise     4.250000   0.070000   4.320000 (  4.468123)
break     0.380000   0.000000   0.380000 (  0.393236)

raise 遅っ!!例外オブジェクトを作るからでしょうね。throw よりも break 2回するほうが早かった。 けど、フラグ用意する手間を考えると throw が一番妥当じゃないですかね。

おわり 

Fluentd Casual Talks #3 で Shadow サーバ用意したら捗った話をしてきた #fluentdcasual

こんにちは @sonots です。

Fluentd Casual Talks #3 at :D
 を開催しました!今回は会場係。思えば去年の Fluentd Casual Talks #2 の2週間ぐらい前にやっと Fluentd を触り始めて Haikanko の話 をしてきたのでした。もう1年も Fluentd やってるのか!!!11

で、今回は「Fluentd で Shadow サーバ用意したら捗った話」をしてきたので資料を置いておきます。最近やっている Fluentd 性能検証の話も合わせて発表してきました。shadow サーバを導入するにあたって最も安定する out_forward のパラメータを紹介しています。

当日の様子は togetter と ustream で見れますので当日の雰囲気を掴みたい方はそちらを見てください。togetter まとめを作ってくれた@shinyaa31 さん、ustream 放送をしてくださった @komamitsu_tw さんありがとうございました!

また会場係を手伝ってくれた @takus@niku4i、そして弊社技術企画の坂東さんありがとうございました!!DeNA++


ruby の String#[] すら使いこなせていなかった情弱でした

String#[] に正規表現を渡せるの知りませんでした。

str = "1.9.3"
str[/\d+.\d+/] #=> 1.9

とかできるんですね。こんなかんじで書いてた。

str = "1.9.3"
md = str.match(/\d+.\d+/)
md[0] #=> 1.9

グループ化は使えるの?と思ったら使えるようですね。マジか、すごいな。ruby-doc にも書いてあった。

str = "1.9.3"
str[/\d+.(\d+)/, 1] #=> 9

情弱でした ... orz

nc コマンドで簡易HTTPサーバ

nc コマンドで簡易に http サーバを立ち上げることができます。大体の *nix ディストリビューションにはデフォルトで入っているので気軽に利用できます。

$ nc -l 8080

これで 8080 番ポートで listen してくれる tcp サーバが立ち上がります.curl http://localhost:8080 とリクエストを送ると nc コマンドに http リクエストの内容が出力されます。個人的には別途 tcpdump しなくても良いこの挙動が大好きです。 

$ nc -l 8080
GET / HTTP/1.1
User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5
Host: localhost:8080
Accept: */*

ただこれだと、レスポンスを何も返していないので、そのまま固まります。この場合は curl コマンドを Ctrl-C で終了しましょう。

レスポンスも返したい場合はパイプで渡せばよいです。

$ ( echo "HTTP/1.0 200 Ok"; echo; echo "Hello World" ) | nc -l 8080

これでちゃんとレスポンスが返ります。

$ curl -v http://localhost:8080
* About to connect() to localhost port 8080
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 8080
> GET / HTTP/1.1
> User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.0 200 Ok
Hello World
* Closing connection #0

ただ1回返すと nc コマンドは終了してしまうので、ずっと起動しておきたい場合は、

$ while true; do ( echo "HTTP/1.0 200 Ok"; echo; echo "Hello World" ) | nc -l 8080; done

のようにループさせる必要があります。あれ、Ctrl-C で死なないですね。Ctrl-z で中断して kill %job で終了させてください ^^;

$ while true; do ( echo "HTTP/1.0 200 Ok"; echo; echo "Hello World" ) | nc -l 8080; done
# ^z
[1] + 6782 suspended
$ kill %1 [1] + 6782 terminated

※ なにかうまい方法ないかな ...

追記:見つけた!

$ while true; do ( echo "HTTP/1.0 200 Ok"; echo; echo "Hello World" ) | nc -l 8080; [ $? != 0 ] && break; done

これで Ctrl-C で終了できました :D
でも長くなって覚えるのめんどくさいから、Ctrl-z でいいや ^^;

さらに追記:これでもイケますね。ってなんだかシェル芸の記事みたいになってきた。。。

$ bash -c 'trap exit INT; while true; do ( echo "HTTP/1.0 200 Ok"; echo; echo "Hello World" ) | nc -l 8080; done' 

A Ruby and Fluentd committer working at DeNA. 記事本文および記事中のコード片は引用および特記あるものを除いてすべて修正BSDライセンスとします。 #ruby #fluentd #growthforecast #haikanko #yohoushi #specinfra #serverspec #focuslight
はてぶ人気エントリー