ラベル Ruby の投稿を表示しています。 すべての投稿を表示
ラベル Ruby の投稿を表示しています。 すべての投稿を表示

2013年11月27日水曜日

Unity の PostprocessBuildPlayer を Ruby で書いてみる(第二版)

UnityでiOSのアプリを作っていて困ることの一つに、iOSが提供するシステムフレームワークへのリンクをプロジェクトに追加するのが超面倒くさいという問題が挙げられます。UnityがiOSアプリを書きだした後、手動でXcode上からシステムフレームワークを追加してもいいのですが、これはとんでもなく面倒です。というわけで、以前こちらの記事でRubyのxcodeprojモジュールを利用して自動的にシステムフレームワークを追加する方法をご紹介しました。
http://akisute.com/2012/09/unity-postprocessbuildplayer-weak.html

今回はそのPostprocessBuildPlayerをさらに機能拡充しましたのでご紹介いたします。主な機能として、
  • システムフレームワークへのリンクをプロジェクトに追加する
    • dylib, framework両方に対応
    • required, optional両方に対応
  • 空のinfo.plistをプロジェクトに追加する
    • ja, enに対応
    • Unity 3時代に空のinfo.plistを追加しないとiOSが提供するUIが英語で表示される問題が合ったため追加
    • Unity 4以上であれば修正されているかも
  • ヘッダサーチパスをライブラリサーチパスからコピーして自動設定する
    • Unity 3時代にビルドにこける事があったので追加
    • Unity 4以上であれば修正されているかも
  • ローンチイメージを自動設定する
    • 容量の関係で極限まで圧縮したjpgをpngの代わりに使いたいということで追加
    • 現在のXcode 5/iOS7向けの環境ではjpgを利用したDefault.pngは全く考慮されていない用に見えるので、使わないほうが無難だと思います
  • main.mmの書き換え
    • ここではSystem.Net.Socket.SocketがSIGPIPEを飛ばしてアプリ全体をクラッシュさせてしまうことがある問題を回避するためにsignalを捕まえたりしています
    • 変更規模が大きいならわざわざここでやるよりUnity側の/Assets/Plugins/iOSにmain.mmを置くほうが良いかと思いますが、ちょっと書き換えるだけなら有用です
  • AppController.mmの書き換え
    • 変更規模が大きいならわざわざここでやるよりUnity側の/Assets/Plugins/iOSにAppController.mmを置くほうが良いかと思いますが、ちょっと書き換えるだけなら有用です
インストール方法は、
  • まずソースコードを取ってきてPostprocessBuildPlayerという名前でUnityプロジェクトの/Assets/Editor/以下に配置します。
  • 実行にはRubyとバージョン0.4.xのxcodeprojモジュールが必要になりますので、インストールします。より大きいバージョンのxcodeprojでは動作未確認ですので、0.4.x系を指定することをおすすめします。
    • sudo gem install xcodeproj --version '~>0.4.0'

ソースコードはこちらになります。MITライセンスです。
#!/usr/bin/env ruby
#
# PostprocessBuildPlayer version 2
# Tested on Ruby 1.8.7, Gem 1.3.6, and xcodeproj 0.4.1
# Created by akisute (http://akisute.com)
# Licensed under The MIT License: http://opensource.org/licenses/mit-license.php
#
require 'rubygems'
# least require version, doesn't work in 0.3.X or less
# possibly work on higher version than 0.4.X, but not tested
gem "xcodeproj", "~>0.4.0"
require 'xcodeproj'
require 'pathname'
require 'fileutils'
#
# Define utility functions
#
def proj_add_system_framework(proj, name) # workaround for 0.4.0 bug of Project#add_system_framework
path = "System/Library/Frameworks/#{name}.framework"
framework_ref = proj.frameworks_group.new_file(path)
framework_ref.name = "#{name}.framework"
framework_ref.source_tree = 'SDKROOT'
framework_ref
end
def proj_add_dylib(proj, name) # added new function, because there's no way we can add dylibs in 0.4.0
path = "usr/lib/#{name}.dylib"
framework_ref = proj.frameworks_group.new_file(path)
framework_ref.name = "#{name}.dylib"
framework_ref.source_tree = 'SDKROOT'
framework_ref
end
def add_system_frameworks_to_project(proj, framework_names, option=:required)
proj.targets.each do |target|
# if target.name == "Unity-iPhone-simulator" then
# next
# end
framework_names.each { |framework_name|
framework = proj_add_system_framework(proj, framework_name) # workaround for 0.4.0 bug of Project#add_system_framework
phase = target.build_phases.find { |phase| phase.is_a?(Xcodeproj::Project::PBXFrameworksBuildPhase) }
ref = phase.add_file_reference(framework)
if option == :optional then
ref.settings = { "ATTRIBUTES" => ["Weak"] }
end
# ref = Xcodeproj::Project::PBXBuildFile.new(proj, nil)
# ref.file_ref = framework
# if option == :optional then
# ref.settings = { "ATTRIBUTES" => ["Weak"] }
# end
# phase = target.build_phases.find { |phase| phase.is_a?(Xcodeproj::Project::PBXFrameworksBuildPhase) }
# phase.files << ref
puts "Added system framework: " + framework_name + " as " + option.id2name
}
end
end
def add_dylibs_to_project(proj, dylib_names, option=:required)
proj.targets.each do |target|
# if target.name == "Unity-iPhone-simulator" then
# next
# end
dylib_names.each { |dylib_name|
dylib = proj_add_dylib(proj, dylib_name)
phase = target.build_phases.find { |phase| phase.is_a?(Xcodeproj::Project::PBXFrameworksBuildPhase) }
ref = phase.add_file_reference(dylib)
if option == :optional then
ref.settings = { "ATTRIBUTES" => ["Weak"] }
end
puts "Added dylib: " + dylib_name + " as " + option.id2name
}
end
end
def new_variant_group_for_group(group, name, sub_group_path=nil)
variant_group = group.project.new(Xcodeproj::Project::PBXVariantGroup)
variant_group.name = name
target = group.find_subpath(sub_group_path, true)
target.children << variant_group
variant_group
end
def add_infoplist_strings_to_project(proj, buildpath)
system("mkdir #{buildpath}/en.lproj")
system("touch #{buildpath}/en.lproj/InfoPlist.strings")
system("mkdir #{buildpath}/ja.lproj")
system("touch #{buildpath}/ja.lproj/InfoPlist.strings")
proj.targets.each do |target|
# if target.name == "Unity-iPhone-simulator" then
# next
# end
infoplist_ref = new_variant_group_for_group(proj.main_group, "InfoPlist.strings")
en_ref = infoplist_ref.new_file("en.lproj/InfoPlist.strings")
en_ref.name = "en"
ja_ref = infoplist_ref.new_file("ja.lproj/InfoPlist.strings")
ja_ref.name = "ja"
buildfile_ref = Xcodeproj::Project::PBXBuildFile.new(proj, nil)
buildfile_ref.file_ref = infoplist_ref
phase = target.build_phases.find { |phase| phase.is_a?(Xcodeproj::Project::PBXResourcesBuildPhase) }
phase.files << buildfile_ref
puts "Added InfoPlist.strings"
end
end
def set_header_search_paths(proj)
proj.targets.each do |target|
# if target.name == "Unity-iPhone-simulator" then
# next
# end
target.build_configuration_list.build_configurations.each do |build_configuration|
header_search_paths = build_configuration.build_settings["LIBRARY_SEARCH_PATHS"]
build_configuration.build_settings["HEADER_SEARCH_PATHS"] = header_search_paths
puts "Added HEADER_SEARCH_PATHS: #{header_search_paths} to build configuration #{build_configuration.name}"
end
end
end
def set_launch_image(proj, unity_project_root_path, buildpath, option)
imagepath = ""
ext = ""
case option
when :png
imagepath = unity_project_root_path + "/Assets/Images"
ext = option.id2name
when :jpg, :jpeg
imagepath = unity_project_root_path + "/Assets/Images/jpg"
ext = option.id2name
system("/usr/libexec/PlistBuddy -c 'Add :UILaunchImageFile string Default.#{ext}' #{buildpath}/Info.plist")
proj.targets.each do |target|
# if target.name == "Unity-iPhone-simulator" then
# next
# end
resource_build_phase = target.build_phases.find { |phase| phase.is_a?(Xcodeproj::Project::PBXResourcesBuildPhase) }
resource_build_phase.files.each do |file|
re = Regexp.new("^(Default.*?)\.png")
if re === file.file_ref.name then
file.file_ref.name = file.file_ref.name.gsub(re, "\\1.#{ext}")
end
if re === file.file_ref.path then
file.file_ref.path = file.file_ref.path.gsub(re, "\\1.#{ext}")
file.file_ref.last_known_file_type = "image.jpeg"
end
end
delete_files = []
sources_build_phase = target.build_phases.find { |phase| phase.is_a?(Xcodeproj::Project::PBXSourcesBuildPhase) }
sources_build_phase.files.each do |file|
re = Regexp.new("^(Default.*?)\.png")
if re === file.file_ref.name then
file.file_ref.name = file.file_ref.name.gsub(re, "\\1.#{ext}")
end
if re === file.file_ref.path then
file.file_ref.path = file.file_ref.path.gsub(re, "\\1.#{ext}")
file.file_ref.last_known_file_type = "image.jpeg"
resource_build_phase.files << file
delete_files << file
end
end
delete_files.each do |file|
sources_build_phase.files.delete(file)
end
end
end
FileUtils.cp("#{imagepath}/Default.#{ext}", "#{buildpath}/Default.#{ext}")
FileUtils.cp("#{imagepath}/Default@2x.#{ext}", "#{buildpath}/Default@2x.#{ext}")
FileUtils.cp("#{imagepath}/Default-568h@2x.#{ext}", "#{buildpath}/Default-568h@2x.#{ext}")
FileUtils.cp("#{imagepath}/Default-Landscape.#{ext}", "#{buildpath}/Default-Landscape.#{ext}")
FileUtils.cp("#{imagepath}/Default-Landscape@2x.#{ext}", "#{buildpath}/Default-Landscape@2x.#{ext}")
FileUtils.cp("#{imagepath}/Default-Portrait.#{ext}", "#{buildpath}/Default-Portrait.#{ext}")
FileUtils.cp("#{imagepath}/Default-Portrait@2x.#{ext}", "#{buildpath}/Default-Portrait@2x.#{ext}")
puts "Added Default images (#{ext}) from #{imagepath}"
end
#
# Define build directory path
# -> Will be suppried as argv if run by Unity
# -> Else, assume unity_project_root_path/build is a build directory
#
unity_project_root_path = File.expand_path(File.dirname($0)) + "/../.."
buildpath = (ARGV[0]) ? ARGV[0] : unity_project_root_path + "/build"
puts "PostprocessBuildPlayer running on build directory: " + buildpath
projpath = buildpath + "/Unity-iPhone.xcodeproj"
proj = Xcodeproj::Project.new(projpath)
###############################################################################
# Example Usages
###############################################################################
#
# Add System frameworks and dynamic libralies to build
#
add_system_frameworks_to_project(proj, ["StoreKit", "Security", "CoreText", "MessageUI"], :required)
add_system_frameworks_to_project(proj, ["Twitter", "Social"], :optional)
add_dylibs_to_project(proj, ["libsqlite3"], :required)
#
# Set HEADER_SEARCH_PATHS
#
set_header_search_paths(proj)
#
# Add UIRequiredDeviceCapabilities to Info.plist
#
system("/usr/libexec/PlistBuddy -c 'Add :UIRequiredDeviceCapabilities: string gyroscope' #{buildpath}/Info.plist")
#
# Update lproj files
#
add_infoplist_strings_to_project(proj, buildpath)
#
# Set Launch Image (Default.png)
#
launch_image_ext = :jpg
set_launch_image(proj, unity_project_root_path, buildpath, launch_image_ext)
#
# Save xcodeproj
#
proj.save_as(projpath)
#
# Rewrite main.mm
# Add uncaught exception handler for better debugging
# Ignores SIGPIPE which rises when application enters background while System.Net.Socket.Socket is open (There's no other way to shut this)
#
f_main_mm = open(buildpath + "/Classes/main.mm", "r")
text_main_mm = f_main_mm.read
f_main_mm.close
f_main_mm = open(buildpath + "/Classes/main.mm", "w")
text_main_mm = text_main_mm.sub(
'int main(int argc, char *argv[])',
'void uncaughtExceptionHandler(NSException *exception);
void uncaughtExceptionHandler(NSException *exception)
{
NSLog(@"%@", exception);
NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
}
int main/*substituted by PostprocessBuildPlayer*/(int argc, char *argv[])'
);
text_main_mm = text_main_mm.sub(
'UnityParseCommandLine(argc, argv);',
'signal(SIGPIPE, SIG_IGN);
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
UnityParseCommandLine/*substituted by PostprocessBuildPlayer*/(argc, argv);'
);
f_main_mm.write(text_main_mm)
f_main_mm.close
puts "Updated: main.mm"
#
# Rewrite AppController.mm
# Fixes UIScrollView problems by rewriting run loop modes
# https://github.com/keijiro/unity-ios-textview
#
# Also fixes problems when you use jpg images as a launch image
#
f_app_controller_mm = open(buildpath + "/Classes/AppController.mm", "r")
text_app_controller_mm = f_app_controller_mm.read
f_app_controller_mm.close
f_app_controller_mm = open(buildpath + "/Classes/AppController.mm", "w")
text_app_controller_mm = text_app_controller_mm.sub(
'while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, kInputProcessingTime, TRUE) == kCFRunLoopRunHandledSource)',
'while (CFRunLoopRunInMode(CFStringRef(UITrackingRunLoopMode), kInputProcessingTime, YES) == kCFRunLoopRunHandledSource)'
);
text_app_controller_mm = text_app_controller_mm.sub(
'[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];',
'[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];'
);
text_app_controller_mm = text_app_controller_mm.sub(
'return [NSString stringWithFormat:@"Default%s%s", orientSuffix, szSuffix];',
'return [NSString stringWithFormat:@"Default%s%s.' + launch_image_ext.id2name + '", orientSuffix, szSuffix];'
);
f_app_controller_mm.write(text_app_controller_mm)
f_app_controller_mm.close
puts "Updated: AppController.mm"
puts "PostprocessBuildPlayer completed."
view raw gistfile1.rb hosted with ❤ by GitHub

余談になりますが、最近ではRubyのxcodeprojを使うのではなく、Pythonのmod-pbxprojを使う方法もあるみたいです。@Seasons氏はこちらの方法を使われているそうです。Pythonのがいい!という方はいかがでしょうか。



2012年9月26日水曜日

Unity の PostprocessBuildPlayer を使って Weak Framework を追加する方法

※2013/11/27追記: 第二版を公開しました。

UnityでiOSのアプリを作っていて困ることの一つに、iOSが提供するシステムフレームワークへのリンクをプロジェクトに追加するのが超面倒くさいという問題が挙げられます。UnityがiOSアプリを書きだした後、手動でXcode上からシステムフレームワークを追加してもいいのですが、これはとんでもなく面倒です。

そこでUnityジャパンの伊藤さんという方が PostprocessBuildPlayer という仕組みと Ruby の xcodeproj ライブラリを使ってビルド時に自動的にシステムフレームワークを追加する仕組みを公表してくださいました。お陰様で随分とはかどっていたのですが、その方法では実はシステムフレームワークをWeakリンク(Optionalリンク)することができなかったのです。これでは例えばSocial.frameworkを使うアプリをビルドしてiOS5で動かすと起動時に問答無用でクラッシュしてしまいます。困りました。iOS6/5両対応ができないと話になりません。

というわけで作りました。システムフレームワークをWeakリンクできるPostprocessBuildPlayerを。こちらです。
#!/usr/bin/env ruby
#
# PostprocessBuildPlayer
# Tested on Ruby 1.8.7, Gem 1.3.6, and xcodeproj 0.3.0
# Created by akisute (http://akisute.com)
# Licensed under The MIT License: http://opensource.org/licenses/mit-license.php
#
require 'rubygems'
require 'xcodeproj'
require 'pathname'
#
# Define utility functions
#
def add_system_frameworks_to_project(proj, framework_names, option=:required)
proj.targets.each do |target|
if target.name == "Unity-iPhone-simulator" then
next
end
framework_names.each { |framework_name|
framework = proj.add_system_framework(framework_name)
ref = Xcodeproj::Project::PBXBuildFile.new(proj, nil, { 'fileRef' => framework.uuid})
if option == :optional then
ref.settings = {"ATTRIBUTES" => ["Weak"] }
end
if target.respond_to?(:build_phases) then
# xcodeproj 0.3.0 or greater
phase = target.build_phases.find { |phase| phase.is_a?(Xcodeproj::Project::PBXFrameworksBuildPhase) }
phase.build_files << ref
else
# xcodeproj 0.1.0
phase = target.buildPhases.find { |phase| phase.is_a?(Xcodeproj::Project::PBXFrameworksBuildPhase) }
phase.files << ref
end
puts "Added system framework: " + framework_name + " as " + option.id2name
}
end
end
#
# Define build directory path
# -> Will be suppried as argv if run by Unity
# -> Else, assume UNITY_PROJECT_ROOT/build is a build directory
#
buildpath = (ARGV[0]) ? ARGV[0] : File.expand_path(File.dirname($0)) + "/../../build"
puts "PostprocessBuildPlayer running on build directory: " + buildpath
#
# Add System frameworks required to build
#
projpath = buildpath + "/Unity-iPhone.xcodeproj"
proj = Xcodeproj::Project.new(projpath)
add_system_frameworks_to_project(proj, ["StoreKit", "Security", "CoreText", "MessageUI"], :required)
add_system_frameworks_to_project(proj, ["Twitter", "Social"], :optional)
proj.save_as(projpath)


ライセンスはMITライセンスにしておきました。
使い方は大体見ればわかるかと思いますが、まず最初にgem経由でxcodeprojをインストールしておくこと。
sudo gem install xcodeproj
あとは上記のPostprocessBuildPlayerをUnityプロジェクトの /Assets/Editor 以下に配置して、コード中のフレームワーク名を指定している箇所をご自身のお好きなように変更してやればオッケーです。

2011年2月12日土曜日

Redmine を Debian 5.0 にゼロからインストールしてみた

あらかじめ注意: 下記のメモは、ruby, gem, rails, rack, redmineのいずれかのバージョンが0.0.1でも違うと動作しない可能性が高いので、当てにしないでください。


■顧客が説明した要件
  • 1つのサーバーに複数のプロジェクトのリポジトリとかリソースをおいているので、1プロジェクトにつき1個インスタンスが必要なtracは都合が悪い!
  • っていうかtrac飽きた!!古い!
  • 複数プロジェクト扱えるBTSが欲しい
  • 見た目クールだといいね、カスタマイズとかできるとすごくいい!
  • Wikiは絶対必須
  • Google Appsと連携できると素敵だな!
  • 簡単にインストールしたい、時間かけたくない


■プロジェクトリーダーの理解
  • https://www.gravitydev.com/ はすごくいいんだけれど許可下りなさそうだなぁ。そもそもWikiがないから却下。
  • となるとやっぱりRedmineかな!あれすごくいいよね!
  • Redmineに移行しようかみたいな話も社内で出てたし、先んじて導入してノウハウ作るのはありだな!


■アナリストのデザイン
[11/02/10 9:24:53] akisute: redmineのインストールが超面倒くさいんだけれど
[11/02/10 9:24:54] akisute: なんとかならんのこれ
[11/02/10 9:25:02] wozozo ( ゚Д゚)y─┛~~: rails
[11/02/10 9:25:19] tokibito: rails
[11/02/10 9:25:20] 文 殊堂: まいんちゃん
[11/02/10 9:26:39] akisute: http://redmine.jp/guide/RedmineInstall/
[11/02/10 9:26:43] akisute: これ見てるとアホかと言いたくなってくる
[11/02/10 9:26:50] akisute: Ruby 1.9には対応していません。 上記の表に示したバージョンのRuby 1.8.xをインストールしてください。
RubyGems 1.3.1以上が必要です。
Rake 0.8.3以上が必要です。
Rack 1.0.1が必要です。1.0.1がインストールされていない場合、データベースマイグレーションが失敗します。
[11/02/10 9:27:25] wozozo ( ゚Д゚)y─┛~~: aptでいれたgemをupdateしようとすると、
[11/02/10 9:27:34] wozozo ( ゚Д゚)y─┛~~: おい待てって言われるし
[11/02/10 9:27:49] aodag: Redmineってライトニングなのないの?
[11/02/10 9:27:53] tokibito: rubyはaptで入れたら死亡する可能性
[11/02/10 9:28:04] aodag: rvmっしょ
[11/02/10 9:28:04] tokibito: 自分でビルドしたほうが無難とかいう
[11/02/10 9:28:11] tokibito: rvmで。


■プログラマのコード
  1. redmine:redmine ユーザーを新規に作成する
    • 以下の作業はすべてredmineユーザーで行う
  2. rvmの最新をインストールする
    • http://rvm.beginrescueend.com/rvm/install/
    • curl と git-core のインストールが必要。aptitude経由で実施
    • /home/redmine/.bashrcの追記を忘れないように
    • source ~/.rvm/scripts/rvm も忘れないように
  3. rvmに必要なパッケージをインストールする
    • こんなんデフォルトで用意しろよ・・・いいかげんにしろ・・・
    • rvm package install readline
    • rvm package install iconv
    • rvm package install zlib
    • rvm package install openssl
    • この順番で入れないと依存関係の問題で怒られます (opensslがzlibを使うとか)
  4. ruby 1.8.7 をrvm経由でインストールする
    • 参考は http://d.hatena.ne.jp/masasuz/20100720/1279635055
    • 先に rvm package install しないとgemが使えない, zlibがないので
    • ビルドオプションを付けることでopensslとzlibを有効にすること
    • rvm install 1.8.7 -C --with-openssl-dir=$HOME/.rvm/usr -C --with-zlib-dir=$HOME/.rvm/usr
    • rvm use 1.8.7
    • ruby --version
    • gem --version
  5. gemのバージョンを 1.3.7 に戻す
  6. 本当にopensslとかzlibとかインストールされているかをチェックする
    • ruby -r openssl -e ""
    • エラーになった場合はopensslの再ビルドを行う。opensslを使えるようにしないとのちのちrakeを実行するところでエラーが発生して先に進めなくなる
    • cd ~/.rvm/src/ruby-1.8.7-p330/ext/openssl
    • ruby extconf.rb --with-opt-dir=$HOME/.rvm/usr/
    • make
    • make install
    • ruby -r openssl -e "" を再度実行してエラーにならない事を確認
  7. rails 2.3.5 をgem経由でインストールする
    • gem install rails -v=2.3.5
    • rails 2.3.5をインストールすると自動的にrack 1.0.1が入るが、先にrack 1.0.1をインストールしておいたほうが良いかも
  8. rack 1.0.1 をgem経由でインストールする
    • gem install rack -v=1.0.1
  9. sqlite3-ruby 1.2.3 をgem経由でインストールする
    • 参考は http://d.hatena.ne.jp/modka/20101208
    • sqlite3-devel (sqlite3.h) が見つからないとインストール出来ないので注意
    • 最新のsqlite3-ruby は sqlite3 3.6.3 が必要で、Debianのaptitudeでは3.5.9までしか無いので、バージョンを指定して古いsqlite3-rubyを入れる
    • sudo aptitude install sqlite3
    • sudo aptitude install libsqlite3-dev
    • gem install sqlite3-ruby -v=1.2.3
  10. i18n 0.4.2 をgem経由でインストールする
    • rakeの実行に必要
    • rakeお前依存関係に含めろや・・・アホか・・・><
    • gem install i18n -v=0.4.2
  11. redmine のリリース版の最新をダウンロードする
  12. データベースの設定を行う
    • 参考は http://redmine.jp/guide/RedmineInstall/
    • 今回はsqlite3
    • cd ~/redmine-1.1.1/config
    • cp database.yml.example database.yml
    • vim database.yml
    • cd ~/redmine-1.1.1
    • rake generate_session_store
    • rake db:migrate RAILS_ENV="production"
    • rake redmine:load_default_data RAILS_ENV="production"
  13. メールの送信設定を行う
    • 不要と思われる。メールが飛ばないだけで済む
  14. 起動する
    • cd ~/redmine-1.1.1/
    • ruby script/server webrick -e production
    • http://localhost:3000/ が立ち上がるので、 admin/admin でログインする
    • 適切にadminのパスワードを変更すること
  15. ログの設定を行う
    • やっとかないとログが溜まりまくって死ぬらしいので
    • cd ~/redmine-1.1.1/config
    • cp additional_environment.rb.example additional_environment.rb
    • vim additional_environment.rb
    • http://redmine.jp/guide/RedmineInstall/ のログの設定セクションのとおりに設定しておく
  16. Passengerをインストールする
    • 参考は http://d.hatena.ne.jp/Umeyashiki/20100131/1264948069
    • gem install passenger
    • passenger-install-nginx-module
    • ここまでの手順どおりに進めていると、大体以下のものが足りないはず
      • Curl development headers with SSL support... not found
      • OpenSSL development headers... not found
      • Zlib development headers... not found
    • 一旦abortしてそれぞれインストールすること
      • sudo aptitude install zlib1g-dev
      • sudo aptitude install libssl-dev
      • sudo aptitude install libcurl4-openssl-dev
    • nginxの再ビルド(ないしソースコード)が必要になるので、すでにapt-getしたnginxがある場合には使えない。その場合はpassengerをstandaloneで起動して、そこに対してnginxからproxy-passなりなんなりする。
    • 以下、passengerスタンドアロンで起動し、redmineはすべてpassengerにやらせる場合を考えます。ただしpassengerのスタンドアロンは内部的にはnginxを使っているので、いずれにせよ上記のインストールは必要になります。
    • cd ~/
    • mkdir log run
    • passenger start redmine1.1.1 -d -a 0.0.0.0 -p 3000 -e production --log-file=log/passenger.log --pid-file=run/passenger.pid
    • ってやると何故か/tmp以下にlogファイルをつくろうとしていみわからないエラー吐いて死ぬので中止
    • cd ~/redmine1.1.1
    • passenger start -d -e production
    • 最低限のオプションだけで起動すれば起動できた


■営業の表現、約束
  • お客様、 redmine をお求めですか?ご安心ください! gem install redmine で一発に決まってますよ!簡単です!
    • そんなものはない
  • それなら sudo apt-get install redmine で一発です!猿でもインストールできます!!
    • Debian では無理
  • それなら最初から redmine がインストールされている vm イメージがあります!こちらを使えば一発です!
    • Ubuntu と SUSE しかない
  • Trac Lightning とかゆとり。真のエンジニアは ruby の configure & build から自分でやって当然(キリッ
    • そんな業務と関係ないところに何時間(何万円)使うつもり?
    • アップデートどうすんの?何時間(何万円)使うつもり?


■プロジェクトの書類

http://redmine.jp/guide/


■実装された運用

http://www.redmine.org/projects/redmine


■顧客への請求金額

akisute の実働5時間分 = 数万円 = https://www.gravitydev.com/pricing のスタンダードプラン数年分


■得られたサポート

http://redmine.jp/guide/RedmineInstall/


■顧客が本当に必要だったもの

http://twitter.com/shin_no_suke/status/35632371084562433
http://twitter.com/hirokinko/status/36307730025156608
http://twitter.com/hirokinko/status/36310634127695872


■元ネタ

http://ryonoda.wordpress.com/2008/09/26/


■一応補足

Redmine自体はすごく良いアプリだと思います。ええ。いま使ってますが、とっても助かってます。

bitnamiの配布しているパッケージが対話環境でもインストールできるというのは知りませんでした。っていうかbitnamiのページのどこにも書いてないんですが・・・><
wget http://bitnami.org/files/stacks/redmine/1.1.1-0/bitnami-redmine-1.1.1-0-linux-installer.bin
chmod +x bitnami-redmine-1.1.1-0-linux-installer.bin
./bitnami-redmine-1.1.1-0-linux-installer.bin --mode text
でうまくいくようです。

しかしこの方法を使うと勝手にApache, MySQL, Ruby, Subversionをインストールされてしまうみたいなので、きちんと管理したいとなるとちょっと不向きかなと。