#!/usr/bin/env ruby require "fileutils" require "yaml" RDBMS = %w(MySQL SQLite3) @src_top = File.dirname( File.expand_path(__FILE__) ) # SET RAILS-COMMAND if RUBY_PLATFORM =~ /mswin|mingw|bccwin/ # FOR WINDOWS $rails_bin = "ruby " + File.join(ENV['RBPATH'],"rails") $dev_null = "null" else # FOR UNIX-LIKE SYSTEMS $rails_bin = "rails" $dev_null = "/dev/null" end # PLUGINS TO BE INSTALLED AFTER RAILS-COMMAND $gfdnavi_plugins = ["acts_as_tree", "acts_as_list"] =begin rails_version = nil # CHECK RAILS VERSION IO.popen("#{$rails_bin} --version"){|io| rails_version = io.read.split[1].split(".")} if (rails_version[0].to_i >= 2) and (rails_version[1].to_i >= 1) if system("git --version > #{$dev_null}") $gfdnavi_plugins.push("git://github.com/mislav/will_paginate.git") else raise "please install \"git\"!!!" end else $gfdnavi_plugins.push("svn://errtheblog.com/svn/plugins/will_paginate") end =end def setup_destination print <<"EOF" Set destination directory name and copy files. gfdnavi will be installed to "/path_you_input/gfdnavi" EOF dest_path = @params[:dest_top] ? File.dirname(@params[:dest_top]) : ENV["HOME"] # Win32 ## unless dest_path == "" if RUBY_PLATFORM =~ /mswin|mingw|bccwin/ dest_path = File.join(ENV['RBPATH'],"..","..") end end print "Please input destination path (default: #{dest_path}): " res = $stdin.gets.chomp! unless res == "" dest_path = res.sub(/\/$/,"") end ########## @params[:dest_top] = File.join(dest_path,"gfdnavi") @params[:skip_rdb] = false if File.exists?( File.join(dest_path, "gfdnavi", "config", "database.yml") ) print "There already exists #{dest_path}/gfdnavi/config/database.yml.\n" print "Do you want to keep the settings? (yes/no, default:yes): " unless $stdin.gets.chomp! == "no" if !$load_inst_params install_params_file = File.join(dest_path,"gfdnavi","install_params.yml") if File.exists?( install_params_file ) @params = YAML.load(File.read(install_params_file)) $load_inst_params = true end end @params[:skip_rdb] = true end end end def setup_parameter if @params[:skip_rdb] print "skipped setting for database configurations\n" else print <<"EOF" *** The database settings you will specify in the following will be written in the file: #{@params[:dest_top]}/config/database.yml YOU CAN MANUALLY EDIT IT LATER IF YOU LIKE. EOF print <<"EOF" *** Please specify the RDBMS you want to use. EOF RDBMS.each_with_index{|name,i| print "#{i+1}. #{name}\n"} print "(Sorry, other RDBMSs are not supported in this installation script.)\n" while true rdb_type = @params[:rdb_type] || 2 print "Select the RDBMS (default:#{rdb_type}): " type = $stdin.gets.chomp! rdb_type = type=="" ? rdb_type : type.to_i unless rdb_type >= 1 && rdb_type <= RDBMS.length print "Invalid number was input.\n" else break end end @params[:rdb_type] = rdb_type if RDBMS[rdb_type-1] == "MySQL" # CYGWIN PATCH BEGIN if /cygwin/ =~ RUBY_PLATFORM print <<"EOF" 1. windows native MySQL 2. MySQL compiled on cygwin EOF while true rdb_plf = @params[:rdb_plf] || 1 print "Select the RDBMS platform (default:#{rdb_plf}): " type = $stdin.gets.chomp! rdb_plf = type=="" ? rdb_plf : type.to_i unless [1,2].include?(rdb_plf) print "Invalid number\n" else break end end @params[:rdb_plf] = rdb_plf end # CYGWIN PATCH END print "Input the RDB user name for gfdnavi_* databases " print "(default: #{@params[:rdb_user]})" if @params[:rdb_user] print ": " rdb_user = $stdin.gets.chomp! @params[:rdb_user] = rdb_user unless rdb_user == "" print "Input the password for the databases: " @params[:rdb_password] = $stdin.gets.chomp! end ### # MySQL SETTINGS if RDBMS[rdb_type-1] == "MySQL" print <<"EOF" You must finish settings of RDBMS before installing gfdnavi. If you have not, use another terminal now to set up an RDBMS. If you would like to use mysql, I can show you how to do that. EOF print "Would you like read the how-to for mysql? (yes/no, default:yes): " unless $stdin.gets.chomp! == "no" print <<"EOF" *** >>>>> doc for mysql >>>>> You can set mysql database as follows: % mysql -u root -p Enter password: -- type in password of root. (the user name specified with the -u option does not need to be root, but it must be a privileged one in order to create new databases.) mysql> create database gfdnavi_development; mysql> create database gfdnavi_test; mysql> create database gfdnavi_production; mysql> grant all on gfdnavi_development.* to 'davis'@'localhost' identified by 'hogehero'; mysql> grant all on gfdnavi_test.* to 'davis'@'localhost' identified by 'hogehero'; mysql> grant all on gfdnavi_production.* to 'davis'@'localhost' identified by 'hogehero'; Here, DO NOT forget to use your own password. DO NOT use 'hogehero'. Note that the password will appear in the database.yml file WITHOUT ENCRYPTION. So DO NOT USE YOUR LOGIN PASSWORD of any computer system either. <<<<< doc for mysql <<<<< EOF end end ### end print "\n***\nGfdanvi configuration\n\n" @params[:skip_configure] = false if File.exists?( File.join(@params[:dest_top], "config", "gfdnavi.yml") ) print "There already exists #{@params[:dest_top]}/config/gfdnavi.yml.\n" print "Do you want to keep the settings? (yes/no, default:yes): " unless $stdin.gets.chomp! == "no" @params[:skip_configure] = true end end if @params[:skip_configure] print "skipped setting for gfdnavi configurations\n" else print <<"EOF" *** The gfdnavi settings you will specify in the following will be written in the file: #{@params[:dest_top]}/config/gfdnavi.yml YOU CAN MANUALLY EDIT IT LATER IF YOU LIKE. EOF print "Set salt for encryption\n" while true print "input phrase (at least 5 characters): " salt = $stdin.gets.chomp! if salt.length < 5 print "The phrase which you input is too short.\n" else break end end @params[:salt] = salt print "Set admin's email address\n" while true print "Input email address" print "(default: #{@params[:email]})" if @params[:email] print ": " email = $stdin.gets.chomp! email = @params[:email] if email == "" unless /^(\w|-)+@(\w|-)+\.(\w|-)+/ =~ email print "Invalid email address is input.\n" else break end end @params[:email] = email print <<"EOF" Select server type to set default configuration parameters The configurations in "config/gfdnavi.yml" will be set according to your choice of server type. 1. private/group server 2. open-access server (enable user accounts) 3. open-access server (disable user accounts) EOF while true print "Select the server type (default:1): " server_type = $stdin.gets.chomp! server_type = server_type=="" ? 1 : server_type.to_i unless [1,2,3].include?(server_type) print "Invalid number was input.\n" else break end end @params[:server_type] = server_type if server_type == 1 # when private server is selected, unlimit soft limit of array. @params[:unlimit_array_soft] = true end print <<"EOF" Select Rails environment. When you use Gfdnavi as an open-access server, production environment is strongly recommended. If you are unsure, you should select development environment. 1. development 2. production EOF while true print "Select environment (default:1): " rails_env = $stdin.gets.chomp! rails_env = rails_env=="" ? 1 : rails_env.to_i unless [1,2].include?(rails_env) print "Invalid number was input.\n" else break end end case rails_env when 1 @params[:rails_env] = "development" when 2 @params[:rails_env] = "production" end end end DIRS_TO_EXCLUDE = /#{@src_top}\/data\/samples\/.+|#{@src_top}\/tmp\/.+|#{@src_top}\/public\/diagrams\/.+/ DIRS_OBSOLETE = /#{@src_top}\/public\/data\/.+/ def copy_files_in_dir(src, dest, sampledata=false) Dir.foreach(src) do |name| next if name == "." || name == ".." next if name == "install.rb" next if /~$/ =~ name dest_name = File.join(dest,name) src_name = File.join(src,name) if File.directory?(src_name) && !File.symlink?(src_name) next if DIRS_OBSOLETE =~ src_name next if !sampledata and (DIRS_TO_EXCLUDE =~ src_name) FileUtils.mkdir(dest_name) unless File.exist?(dest_name) copy_files_in_dir( src_name, dest_name, sampledata) else FileUtils.copy( src_name, dest_name, {:preserve => true} ) if File.file?(src_name) end end end def copy_files(src, dest, sampledata=false) copy_files_in_dir(src, dest, sampledata) end def install_files dest_top = @params[:dest_top] if File.exists?( dest_top ) unless File.directory?(dest_top) abort "#{dest_top} is not a directory." end # IF TARGET DIRECTORY ALREADY EXISTS if @src_top != dest_top # IF TARGET != SRC print "#{dest_top} already exists.\n" unless $noquestions while true print "Can I overwrite it? (yes/no): " case $stdin.gets.chomp! when "yes" # OVERWRITE print "#{dest_top} will be overwritten.\n" break when "no" # KEEP CURRENT FILES print <<"EOF" #{dest_top} will be kept as is. Install process may fail if you have not installed gfdnavi to the directory. EOF return end end end else # IF TARGET == SRC print "You are going to use current directory as the target.\n" end dest_existed = true else # CREATE TARGET DIRECTORY unless $noquestions print "#{dest_top} does not exist.\n" print "Can I create the directories? (yes/no, default:yes): " make_dest_top = $stdin.gets.chomp! else make_dest_top = "yes" end unless make_dest_top == "no" FileUtils.makedirs(dest_top) else # CANCEL abort "operation was canceled." end dest_existed = false end Dir.chdir( File.join(@params[:dest_top],"..") ) # CHECK IF RAILS-COMMAND WILL BE EXECUTED execute_rails = false if dest_existed && File.exists?( File.join(dest_top,'script/about') ) && (!$noquestions) print "Do you want execute \"rails\" command? (you seem to have already executed, but it's no problem to repeat it.)(no/yes, default:no): " if $stdin.gets.chomp! == "yes" execute_rails = true end else execute_rails = true end unless execute_rails # IF NOT EXECUTING RAILS-COMMAND print <<"EOF" Warning: You selected no. Make sure that you have already executed rails command, or execute rails later. EOF else if @params[:skip_rdb] || (@src_top == dest_top) rails_option = "--skip" else rails_option = "--force" end # EXECUTE RAILS-COMMAND railscommand = "#{$rails_bin} gfdnavi #{rails_option} -d #{RDBMS[@params[:rdb_type]-1].downcase} > #{$dev_null}" unless system(railscommand) abort "failed to execute \n #{railscommand}\nat #{Dir.pwd}" end # INSTALL PLUGINS IF RAILS >= 2.0 require "rubygems" begin if (gem "rails", ">=2.0") Dir.chdir("gfdnavi") # REMOTE PLUGINS skip_remote_plugin = false plugincommand = "ruby script/plugin install --force" $gfdnavi_plugins.each{|plgin| plugincommand << " " << plgin} # CHECK PROXY proxycommand = "" if http_proxy = (ENV["http_proxy"] || ENV["HTTP_PROXY"]) print "use proxy for http connection\n" print "http_proxy = #{ENV["http_proxy"]}\n" if ENV["http_proxy"] print "HTTP_PROXY = #{ENV["HTTP_PROXY"]}\n" if ENV["HTTP_PROXY"] else unless $noquestions print <<"EOF" You need http connection to install remote plugins. If you are not connected to internet, please \"skip\" and try later. Which do you choose? (direct / proxy / skip, default:direct): EOF case $stdin.gets.chomp! when "proxy" # SET HTTP PROXY print "enter proxy (http://your-proxy-sever:port):\n" http_proxy = $stdin.gets.chomp! ENV["http_proxy"] = http_proxy when "skip" # SKIP REMOTE PLUGINS print <<"EOF" You need to execute following command at #{Dir.pwd} later. #{plugincommand} EOF skip_remote_plugin = true end else print "connecting without proxy\n" end end unless skip_remote_plugin # INSTALL REMOTE PLUGINS print "install remote plugins...\n" unless system(plugincommand) print <<"EOF" failed to execute #{plugincommand} with http_proxy = #{http_proxy} at #{Dir.pwd} Before you start the service, please try again. EOF end end end rescue Gem::LoadError # NO NEED TO INSTALL PLUGINS IF RAILS 1.x end end # COPY (OVERWRITE) ORIGINAL FILES TO THE DESTINATION if @src_top != dest_top copy_files( @src_top, dest_top ) unless $noquestions print "Do you want to install sample data? (yes/no, default:yes): " inst_sample = $stdin.gets.chomp! else inst_sample = "yes" end unless inst_sample == "no" dest_sample_dir = File.join(dest_top,"data","samples") FileUtils.mkdir( dest_sample_dir ) unless File.exists?( dest_sample_dir ) copy_files( File.join(@src_top,"data","samples"), dest_sample_dir , sampledata=true) end else printf("src == dest. no need to copy files.\n") end end def set_configure_files Dir.chdir( @params[:dest_top] ) unless @params[:skip_rdb] database_file = File.join("config","database.yml") # RAILS COMMAND CREATES database.yml # THUS IT EXIST ALL THE TIME if File.exists?( database_file ) FileUtils.move( database_file, database_file + ".bak" ) end rdb_type = @params[:rdb_type] rdb_plf = @params[:rdb_plf] name = %w(mysql sqlite3)[rdb_type-1] File.open(database_file,"w"){|file| File.foreach( database_file + ".example" ){|line| if RDBMS[rdb_type-1] == "MySQL" if /^(\s*username:)/ =~ line line = "#$1 #{@params[:rdb_user]}\n" elsif /^(\s*password:)/ =~ line line = "#$1 #{@params[:rdb_password]}\n" end if RUBY_PLATFORM =~ /mswin|mingw|bccwin/ # FOR WINDOWS else # FOR UNIX-LIKE PLATFORMS if rdb_plf == 1 # FOR WINDOWS NATIVE MySQL WITH Cygwin Ruby if /^(\s*host:)/ =~ line # not Unix Socket but TCP/IP port line = "#$1 127.0.0.1\n" elsif /^(\s*socket:)/ =~ line # do nothing end else if /^(\s*socket:)/ =~ line # configuration for MySQL Unix Socket # search for MySQL Socket sockets = ["/tmp/mysql.sock", # default "/var/lib/mysql/mysql.sock", # fedora, vine "/var/run/mysqld/mysqld.sock" # debian ] tmp_sockets = [] sockets.each{|s| tmp_sockets.push(s) if File.exist?(s) } if tmp_sockets > 1 raise "More than 1 MySQL sockets found!!!" elsif tmp_sockets == 1 line = "#$1 #{tmp_sockets[0]}" else raise "MySQL socket not found!!!" end end end end elsif RDBMS[rdb_type-1] == "SQLite3" if /^(\s*adapter:)/ =~ line # CHANGE ADAPTER TO SQLite3 line = " adapter: sqlite3\n" elsif /^(\s*database:.*development)/ =~ line line = " database: db/development.sqlite3" elsif /^(\s*database:.*test)/ =~ line line = " database: db/test.sqlite3" elsif /^(\s*database:.*production)/ =~ line line = " database: db/production.sqlite3" elsif /^(\s*username:)/ =~ line line = "" elsif /^(\s*password:)/ =~ line line = "" elsif /^(\s*host:)/ =~ line line = "" end end file.write line } } end unless @params[:skip_configure] config_file = File.join("config","gfdnavi.yml") if File.exists?( config_file ) FileUtils.move( config_file, config_file + ".bak" ) end File.open(config_file,"w") do |file| server_type = @params[:server_type] salt = @params[:salt] email = @params[:email] rails_env = @params[:rails_env] File.foreach( config_file + ".example" ){|line| if /^(passphrase:)/ =~ line line = "#$1 #{salt}\n" elsif /^(\s*email:) root@example\.org/ =~ line line = "#$1 #{email}\n" end if server_type == 1 # private elsif server_type > 1 # open if /^(disable_user:)/ =~ line if server_type == 3 # disable user accounts line = "#$1 true\n" end elsif /^(enable_email:)/ =~ line line = "#$1 true\n" elsif /^(:domain:) example\.org/ =~ line key = $1 /[\w|-]*@(.+)/ =~ @email line = "#{key} #$1\n" end end if rails_env == "development" elsif rails_env == "production" if /^#(\s*RAILS_ENV:)/ =~ line line = "#$1 #{rails_env}\n" end end #p ["@params[:unlimit_array_soft]",@params[:unlimit_array_soft]] if @params[:unlimit_array_soft] #hoge if /^soft_limit_array_size: 2000000/ =~ line line = "#" + line end end file.write line } end end end def execute_setup Dir.chdir(@params[:dest_top]) begin if Variable.table_exists? print <<"EOF" If you already have data in the gfdnavi database, skip this step, and execute "rake update" manually if it is necessary. EOF unless $noquestions print "Do you skip? (no/yes, default:no): " if $stdin.gets.chomp! == "yes" print "skiped\n" return end end end rescue #puts $! end # WHILE EXECUTION OF RAKE SETUP, WE NEED TO REPLY TO QUESTIONS # DO NOT OUTPUT TO /dev/null unless $noquestions_rake rake_task = "setup" else rake_task = "setup_noquestions" end if RUBY_PLATFORM =~ /mswin|mingw|bccwin/ rakecommand = "rake.bat #{rake_task}" else rakecommand = "rake #{rake_task}" end unless system(rakecommand) abort "failed to execute \"rake #{rake_task}\" at #{Dir.pwd}\n" end end def print_parameters print <<"EOF" Gfdnavi will be installed to the following directory: #{@params[:dest_top]} with following settings: RDBMS: #{RDBMS[@params[:rdb_type] - 1]} #{if @params[:rdb_type]==1;if @params[:rdb_plf]==1;'on Windows';else;'on Cygwin';end;end} salt for encryption: #{@params[:salt]} email: #{@params[:email]} server type: #{@params[:server_type]} unlimit array size (soft limit): #{@params[:unlimit_array_soft] ? "true" : "false"} rails env: #{@params[:rails_env]} EOF end #################### ### MAIN PROGRAM ### #################### if (ARGV.delete("--help") || ARGV.delete("-h")) print <<"EOF" This is Gfdnavi installer. Options: --noquestions : Install with default settings --clean : Discard previous settings -h, --help : Print this message EOF exit 0 end if ARGV.delete("--noquestions") $noquestions = true $noquestions_rake = true end $load_inst_params = false install_params_file = File.join(@src_top,"install_params.yml") if File.exists?( install_params_file ) unless ARGV.delete("--clean") @params = YAML.load(File.read(install_params_file)) $load_inst_params = true end end @params = Hash.new unless Hash === @params # DEFAULT SETTINGS if @params[:dest_top] dest_path = File.dirname(@params[:dest_top]) else if RUBY_PLATFORM =~ /mswin|mingw|bccwin/ dest_path = File.join(ENV['RBPATH'],"..","..") else dest_path = ENV["HOME"] @params[:dest_top] = File.join(dest_path,"gfdnavi") end end # SQLite3 @params[:rdb_type] = 2 if !(@params[:rdb_type]) @params[:rails_env] = "production" if !(@params[:rails_env]) # Windows native MySQL if MySQL with cygwin @params[:rdb_plf] = 1 if !(@params[:rdb_plf]) # @params[:salt] = [rand(64),rand(64)].pack("C*").tr("\x00-\x3f","A-Za-z0-9./") @params[:email] = "mail@hoge.com" if !(@params[:email]) @params[:server_type] = 1 if !(@params[:server_type]) @params[:rails_env] = "production" if !(@params[:rails_env]) @params[:skip_rdb] = false @params[:skip_configure] = false print <<"EOF" Welcome to Gfdnavi. In order to install Gfdnavi, there are the following steps. Step 1: Setup parameters Step 2: Execute rails and copy files" Step 3: Create "database.yml" and "gfdnavi.yml" Step 4: Execute "rake setup" Step 5: Set root's password press any key to continue EOF unless $noquestions $stdin.gets end unless $noquestions mode_confirm = false begin print <<"EOF" Select install mode: 1. install private server with default settings 2. install public server with default settings 3. configure details EOF while true case $stdin.gets.chomp! when "1" @params[:server_type] = 1 @params[:unlimit_array_soft] = true $noquestions = true setup_destination print_parameters print "Do you agree? (yes/no, default:no):" mode_confirm = true if ($stdin.gets.chomp!)=="yes" break when "2" @params[:server_type] = 2 $noquestions = true setup_destination print_parameters print "Do you agree? (yes/no, default:no):" mode_confirm = true if ($stdin.gets.chomp!)=="yes" break when "3" mode_confirm = true setup_destination break else print "invalid number!\n" end end end until mode_confirm end print "***************************************\nStep 1: Setup parameters\n" unless $noquestions setup_parameter para = @params.dup para.delete(:salt) para.delete(:rdb_password) File.open(install_params_file,"w"){|file| file.write para.to_yaml } else print "Skip\n" end print "***************************************\nStep 2: Execute rails and copy files\n" install_files print "***************************************\nStep 3: Create \"database.yml\" and \"gfdnavi.yml\"\n" set_configure_files print "***************************************\nStep 4: Execute rake setup\n" require File.join(Dir.pwd, "config", "environment") execute_setup print <<"EOF" Congraturations! You sucessed to install gfdnavi to #{@params[:dest_top]}. Before you start gfdnavi, change the following configurations 1. "config/database.yml" 2. "config/gfdnavi.yml" and check file permission mode of their files (only webserver can read the files). EOF