Chefを使ってCentOS6.5でruby-1.8.7をrbenvからインストールしようとすると失敗するが、インストール出来るようにした

# Chefを使ってCentOS6.5でruby-1.8.7をrbenvからインストールしようとすると失敗するが、インストール出来るようにした

## 問題の概要

CentOS6.5でruby-1.8.7をコンパイルすると、opensslの部分でコンパイルエラーになる。

```
ossl_pkey_ec.c: In function 'ossl_ec_group_initialize':
ossl_pkey_ec.c:761: warning: assignment makes pointer from integer without a cast
ossl_pkey_ec.c:815: error: 'EC_GROUP_new_curve_GF2m' undeclared (first use in this function)
ossl_pkey_ec.c:815: error: (Each undeclared identifier is reported only once
ossl_pkey_ec.c:815: error: for each function it appears in.)
```

CentOSのopensslパッケージがruby-1.8.7が作成された頃より新しくなったのだが、そのためにミスマッチが生じているらしい。
これの対処法をググると、2つ出てくる。

1. そのうちopensslの新しいパッケージが出るだろうから、その時に yum install すれば直るだろうから、しばし待て
2. rubyのossl_pkey_ec.c にパッチを当てろ → https://gist.github.com/hyoshida/11241844

当然2で対応する訳だが、rbenv install にてコンパイルするので、どこでパッチを当てるかという問題になる。
chefからrubyソースにパッチを当てるのか、chefがruby-buildにパッチを当て、ruby-buildがrubyソースにパッチを当てるのか？

最初は、パッチを当てたrubyソースをgithubに置いておきそれをダウンロードするようにして、またruby-buildに専用のバージョン定義ファイルを入れたものを作ってこれもgithubに置いておくようにしていた。
これだとcookbook以外に外部ファイルを2つも置くことになり情報が分散していてよろしくないので、cookbookだけで何とかする方法を探していたが、やり方がわかった。

## ruby-buildバージョン定義ファイル中でパッチを当てる

ruby-buildのバージョン定義ファイル内で、rubyソースにパッチを当てる方法がわかった。
定義ファイルはシェルスクリプトであり、その中で before_install_package() 関数を定義してやれば、インストール直前に呼び出される。
この関数の中でパッチを当ててやればいい。

出来た定義ファイルがこれ。

```bash:ruby_build/share/ruby-build/1.8.7-p374-centos_openssl
before_install_package() {
  if [ "$1" != "ruby-1.8.7-p374" ]; then
    return 0
  fi
  patch -d ${BUILD_PATH}/ruby-1.8.7-p374 -p1 <<PATCH_END
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index cbdad3f..d517b58 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -757,8 +757,10 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
                 method = EC_GFp_mont_method();
             } else if (id == s_GFp_nist) {
                 method = EC_GFp_nist_method();
+#if !defined(OPENSSL_NO_EC2M)
             } else if (id == s_GF2m_simple) {
                 method = EC_GF2m_simple_method();
+#endif
             }
 
             if (method) {
@@ -811,8 +813,10 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
 
             if (id == s_GFp) {
                 new_curve = EC_GROUP_new_curve_GFp;
+#if !defined(OPENSSL_NO_EC2M)
             } else if (id == s_GF2m) {
                 new_curve = EC_GROUP_new_curve_GF2m;
+#endif
             } else {
                 rb_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
             }
PATCH_END
  echo "openssl patch applied" >&2
}
require_gcc
install_package "ruby-1.8.7-p374" "http://cache.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p374.tar.gz#876eeeaaeeab10cbf4767833547d66d86d6717ef48fd3d89e27db8926a65276c" auto_tcltk standard
install_package "rubygems-1.6.2" "http://production.cf.rubygems.org/rubygems/rubygems-1.6.2.tgz#cb5261818b931b5ea2cb54bc1d583c47823543fcf9682f0d6298849091c1cea7" ruby
```

これをcookbookの file/ の下に置いておき、レシピ中でruby_buildのダウンロード後に転送してやればいい。

クックブック rbenv を呼び出すので、Berksfile に入れ、metadataにもdependsを記述する。

```ruby:Berksfile
cookbook 'rbenv'
```

```ruby:metadata.rb
depends          'rbenv'
```

これがレシピ。

```ruby:recipes/default.rb
include_recipe "rbenv::default"
include_recipe "rbenv::rbenv_vars"
include_recipe "rbenv::ruby_build"

cookbook_file "#{node[:ruby_build][:prefix]}/share/ruby-build/1.8.7-p374-centos_openssl" do
  source "1.8.7-p374-centos_openssl"
  mode '0644'
  owner node[:rbenv][:user]
  group node[:rbenv][:group]
end

rbenv_ruby "1.8.7-p374-centos_openssl" do
  ruby_version "1.8.7-p374-centos_openssl"
end
```

cookbookだけで完結してすっきり。