Capistrano3 で Unicorn の再起動に失敗したのを対応したメモ

By | 2014年2月15日

たまにデプロイした際に Unicorn の再起動で失敗することがありました。
調べてみると「Capistrano によるデプロイ時に Unicorn の再起動に失敗することがある問題への対処」に書かれているのと同じ原因でした。

Unicorn の再起動時に、 Gemfile に新たに追加された gem を Bundler が読み込めていないことがわかった。 だから require している箇所で LoadError が発生Pする。 新しくなった Gemfile を Bundler がうまくロードできていないようだ。

元記事では Capistrano2 で run に環境変数を設定したものを文字列で渡して起動させているのですが、 ‘capistrano-bundler’ や ‘capistrano-rbenv’ を使っているので文字列で指定せずに環境変数を指定するやり方を調べてみました。

Capistrano3 の設定は「unicorn + rails 用 Capistrano 3 の設定ファイル」を使っています。

More Expressive Command Language」 によると with を使えばできるみたいです。以下が diff です。

# lib/capistrano/tasks/unicorn.cap
 
   def start_unicorn
      within current_path do
 -      execute :bundle, :exec, :unicorn, "-c #{fetch(:unicorn_config)} -E #{fetch(:rails_env)} -D";
 +      with bundle_gemfile: "#{current_path}/Gemfile"; do
 +        execute :bundle, :exec, :unicorn, "-c #{fetch(:unicorn_config)} -E #{fetch(:rails_env)} -D";
 +      end
      end
    end

これでめでたく再起動に失敗することがなくなりました。

起動時に環境変数を指定するだけでなく、Unicorn の設定ファイルで BUNDLE_GEMFILE の環境変数を指定して解決する方法もあります。「Tips for using Unicorn with Sandbox installation tools」の ‘BUNDLE_GEMFILE for Capistrano users’ にかかれています。

# unicorn.rb
 
before_exec do |server|
 ENV['BUNDLE_GEMFILE'] = '/path/to/app/current/Gemfile';
end

#confwd で CocoaPods の Plugin の作り方について LT してきた

By | 2014年2月11日

少し遅れましたが「Conference With Developers 2」で LT をさせてもらいました。

@ninjinkun さんが発表していた「GitHub活動を通して個人のキャリアを積みつつ仕事の成果を出す方法」の中にGitHub チャンスというフレーズがあります。
便利なライブラリや意外にもこういう普段使ってるようなエコシステムの中にも GitHub チャンスは埋もれているので気軽に作って公開することでチャンスを生かせるかもしれませんね。
個人的には CocoaPods の Plugin は本家に取り入れられる可能性もあるので結構チャンスが埋もれてるのではないかと思っています。

また運営者の方々はこのような素敵なイベントを開催していただきありがとうございました。次回も参加したいと思います。

と、ここまでは感想なのですが、LT の中で CocoaPods Plugin の作り方の詳細 は blog に書くと言ってしまってましたが 以下がそれです。

この記事を書いた時の各 gem の version です。

gem の作り方ですが「君がOpsでもRubyで書いたライブラリはGemで配ろう」がとてもまとまっていてわかりやすいです。

plugin を作る際に参考になるのが cocoapods-try-release-fixcocoapods-0.29.0/lib/cocoapods/command 以下のコードが分かりやすいです。コード量も少ないので読めばある程度理解できるかと思います。

重要になってくるのが pod コマンドを実行した時の処理の流れです。

1. プラグイン読み込み(lib/cocoapods_plugin.rb が require される)
2. 該当するコマンドの instance を作成
3. 作成した instance の validate! を実行
4. 作成した instance の run
(claid-0.4.0/lib/claide/command.rb 参照)

これさえ把握できていれば後は簡単です。
サンプル用に引数を出力する echo コマンドを作ってみました。

$ git clone git://github.com/dealforest/sandbox.git
$ cd sandbox/cocoapods-echo
$ rake install
$ pod echo hogehoge
hogehoge
$ pod echo --test hogehoge
test

bundle gem cocoapods-echo を実行した後の diff です。
説明については GitHub 上にしておいたので分からない場合はコメントをもらえればレスします。

clone してきて rake install をしてもらえれば pod echo を実行できます。

ではでは。

cocoapods で homepage を開くコマンドを作ったお話

By | 2013年12月28日

みなさん cocoapods を使って久しいかと思います。
僕がよくやるのが pod seach で検索して Homepage(大体githubのページ) を開いて README, 履歴, コードをざっと確認してそのライブラリを使うかどうか確認していました。

ただこれがいくつもあるとコピペで繰り返すのは面倒くさい作業でした。

このツイートを見て try くそ便利だなと。
コマンドで browser を開ければいけてるやん!!
と思って早速調べてみました。
cocoapods には plugin 機構があり、簡単にできそうなので作ってみました。

使い方は簡単で gem で install するだけで使えます。

gem install cocoapods-browser

あとは気になった pod を引数に渡すと browser で podspec で指定している homepage(おそらくgithubのページ) を開くことができます。
pod は複数指定することもできます。

pod browser PODNAME

dealforest/cocoapods-browser

プルリクもらえればとりこみまっす。
ではでは〜

追記1

便利そうなので追加しました。

pod browser PODNAME --spec

これで https://github.com/dealforest/iOS-FakeWeb/blob/master/iOS-FakeWeb.podspec を開くようになります。

追記2

Naming (browse instead of browser) のアドバイスより version 0.1.0 からコマンド名が browse になりました。

pod browse PODNAME
Posted in ios

iOS7 で UITableViewCell の深度を変更する時に気をつけること

By | 2013年10月25日

UITableView に対して bringSubviewToFront: のメッセージを送って UITableViewCell の深度を変更していたですけど
iOS7 からだと深度がかわらんなくなって困ったというお話です。

原因は iOS7 と iOS6 とで UITableView の構造が変わったためです。
iOS6 では UITableViewCell を UITableView が抱えていたのですが
iOS7 からは UITableViewWrapperView が間に加わりそいつが UITableViewCell を抱えてます。

[iOS6]
UITableView
    ├── UITableViewCell
    ├── ...
    └── UITabelViewCell

[iOS7]
UITableView
    └── UITableViewWrapperView
                   ├── UITableViewCell
                   ├── ...
                   └── UITableViewCell

bringSubViewToFront: は抱えてる view に対して実行してやる必要がるので
iOS7 の場合は UITableViewWrapperView に対して実行してやれば深度が変更されるというわけです。

とはいえ UITableView から UITableViewWrapperView にアクセスができません。
正確には subviews をたどればできるけど諸々考慮すると最終手段にしておきたい手段です。

superview が抱える view を指しているので、ようするに UITableViewCell の superview に対して実行してやれば
iOS7 と iOS6 共に同一のコードで深度が変更できます。

[旧]: [tableView bringSubViewToFront:cell]
[新]: [cell.superview bringSubViewToFront:cell]

元から UITableViewCell の superview をたどってメッセージを投げていれば問題なかったというわけです。
つまりは構造が変わってるから気をつけろよといったお話ですね。はい。
今回のとは関係ありませんが UITableViewCell の構造も変わったので注意しないといけないですね。

あと、iOS6 の時は深度変更した際にスクロールバーが消えるバグがあったんですけど iOS7 では直っていました。
iOS6 では 「UITableViewCell の深度を変更した時に scrollbar を正常に表示する方法」で表示することができますがパフォーマンスは若干落ちます。

Posted in ios

UITableViewCell の深度を変更した時に scrollbar を正常に表示する方法

By | 2013年7月27日

UITableView をハックして Feedly ライクな UITableView を作ってたのですが scrollViewDidScroll: で UITableViewCell の深度を無理矢理いじったりしたせいで scrollbar が UITableViewCell の後ろに隠れるようになって困ってました。
地味にこういうのは気になって仕方がないたちです。

で、解決方法がわかったのでメモがわりに残しておきます。
UITableViewCell の深度を変更する前に UITableView のプロパティ “showsVerticalScrollIndicator” をオフにして深度変更後に再度オンにすれば scrollbar が表示されるようになります。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    [self.tableView setShowsVerticalScrollIndicator:NO];     // ここ超重要!!!
 
    for (UITableViewCell *cell in [self.tableView visibleCells])
        [self.tableView bringSubviewToFront:cell];
 
    [self.tableView setShowsVerticalScrollIndicator:YES];     // ここ超重要!!!
}

サンプルは github にあげてあります。
この辺りのコードを変更してもらえれば確認できるかと思います。

Posted in ios