locarails 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,240 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created on 2008-8-19.
4
+ # Copyright (c) 2008. All rights reserved.
5
+ # Fabio Akita - akitaonrails.com
6
+
7
+ begin
8
+ require 'rubygems'
9
+ rescue LoadError
10
+ # no rubygems to load, so we fail silently
11
+ end
12
+
13
+ require 'ostruct'
14
+ require 'optparse'
15
+ require 'erb'
16
+ require 'highline/import'
17
+
18
+ # configuracoes da sua hospedagem
19
+ class MyOpenStruct < OpenStruct
20
+ def blank?(campo)
21
+ send(campo).nil? || send(campo).empty?
22
+ end
23
+
24
+ def input(campo, message, default_value = nil)
25
+ unless blank?(campo)
26
+ puts "* #{message} > #{message =~ /senha/ ? "********" : send(campo)}"
27
+ return send(campo)
28
+ end
29
+ result = if message =~ /senha/
30
+ ask("* #{message} > ") { |q| q.echo = "*" }
31
+ else
32
+ ask("* #{message} > ")
33
+ end
34
+ send("#{campo}=", (default_value && result.empty?) ? default_value : result)
35
+ end
36
+ end
37
+
38
+ config = MyOpenStruct.new
39
+ mysqlcfg = MyOpenStruct.new
40
+
41
+ # defaults
42
+ config.force = false
43
+ config.mode = 'copy'
44
+
45
+ OptionParser.new do |opts|
46
+ opts.banner = <<-STR
47
+ LocaRails - configurador de Capistrano para projetos Rails
48
+ especifico para hospedagens Linux da Locaweb
49
+
50
+ Uso: #{File.basename($0)} [caminho] [opcoes]
51
+ STR
52
+
53
+ opts.on("--version", "Mostra versao atual do locarails") do
54
+ require 'locarails'
55
+ puts "Locarails v#{Locarails::VERSION::STRING}"
56
+ exit 0
57
+ end
58
+
59
+ opts.on("-h", "--help", "Mostra esta tela de ajuda") do
60
+ puts opts
61
+ exit 0
62
+ end
63
+
64
+ opts.on("-m", "--mode=tipo", "modo de deployment (copy/git)", "Padrao: copy") do |mode|
65
+ config.mode = mode
66
+ unless "copy|git".include?(mode)
67
+ puts "#{mode} nao existe. Escolha copy ou git como --mode."
68
+ exit 0
69
+ end
70
+ end
71
+
72
+ opts.on("-s", "--sshkey=caminho", "local da sua chave privada SSH", "Padrao: ~/.ssh/id_rsa") do |path|
73
+ config.ssh_key_path = path
74
+ unless File.exists?(path)
75
+ puts "Chave inexistente no caminho #{path}."
76
+ exit 0
77
+ end
78
+ end
79
+
80
+ opts.on("-f", "--force", "Sobrescreve seu config/deploy.rb, caso exista.", "Cuidado: voce ira perder sua configuracao anterior") do
81
+ config.force = true
82
+ end
83
+
84
+ opts.on("-u", "--usuario=login", "Usuario da hospedagem Linux") do |usuario|
85
+ config.usuario = usuario
86
+ end
87
+
88
+ opts.on("-a", "--aplicacao=aplicacao", "Nome da sua aplicacao", "O mesmo do apontamento /public_html/aplicacao") do |aplicacao|
89
+ config.app_name = aplicacao
90
+ end
91
+
92
+ opts.on("-d", "--dominio=URL", "Dominio do seu site", "ex. www.seu_dominio.com") do |dominio|
93
+ config.dominio = dominio
94
+ end
95
+
96
+ opts.on("-q", "--banco=banco", "Nome do seu banco de dados") do |db|
97
+ mysqlcfg.db = db
98
+ end
99
+
100
+ opts.on("-l", "--banco-usuario=login", "Login do seu banco de dados MySQL") do |dbuser|
101
+ mysqlcfg.user = dbuser
102
+ end
103
+
104
+ opts.on("-p", "--banco-senha=senha", "Senha do seu banco de dados MySQL") do |dbpass|
105
+ mysqlcfg.pass = dbpass
106
+ end
107
+
108
+ opts.on("-v", "--banco-servidor=servidor", "Servidor do seu banco de dados", "ex. mysql6666.locaweb.com.br") do |dbhost|
109
+ mysqlcfg.host = dbhost
110
+ end
111
+
112
+ opts.on("-b", "--git-branch=branch", "Branch local do seu repositorio Git", "padrao: master") do |gitbranch|
113
+ config.branch = gitbranch
114
+ end
115
+
116
+ opts.on("-r", "--git-remote=remote", "Nome do repositorio remoto gravado no seu .git/config", "padrao: locaweb") do |gitname|
117
+ config.remote_repo = gitname
118
+ end
119
+
120
+ begin
121
+ opts.parse!(ARGV)
122
+ rescue OptionParser::ParseError => e
123
+ warn e.message
124
+ puts opts
125
+ exit 1
126
+ end
127
+ end
128
+
129
+ if ARGV.empty?
130
+ abort "Por favor, especifique o diretorio do seu projeto Rails, e.g. `#{File.basename($0)} .'"
131
+ elsif !File.exists?(ARGV.first)
132
+ abort "`#{ARGV.first}' nao existe. Tente novamente."
133
+ elsif !File.directory?(ARGV.first)
134
+ abort "`#{ARGV.first}' nao eh um diretorio. Tente novamente."
135
+ end
136
+
137
+ # configuracoes locais da sua maquina
138
+ config.bin_path = File.dirname(File.expand_path(__FILE__))
139
+ config.local_path = File.expand_path(ARGV.shift)
140
+ config.app_name ||= config.local_path.split('/').last
141
+
142
+ if !config.force && File.exists?(File.join(config.local_path, 'config/deploy.rb'))
143
+ abort "Voce ja tem capistrano configurado em config/deploy.rb. Configuracao abortada."
144
+ end
145
+
146
+ puts <<-STR
147
+ ========================================================
148
+ Bem Vindos ao configurador de projetos da Locaweb.
149
+
150
+ Vamos configurar seu projeto Rails para melhor se
151
+ Adequar nas nossas hospedagens Linux compartilhada.
152
+
153
+ O comando locarails deve ser executado *dentro* do
154
+ diretorio do seu projeto, na sua maquina local.
155
+
156
+ Para tanto precisaremos de algumas informacoes:
157
+ ========================================================
158
+
159
+ Estrategia de instalacao via: #{config.mode}
160
+
161
+ Garanta que a seguinte pasta contem sua aplicacao Rails:
162
+ #{config.local_path}
163
+
164
+ STR
165
+
166
+ # configuracoes inseridas manualmente pelo usuario
167
+ config.input( :app_name, "Nome da sua aplicacao" )
168
+ config.input( :dominio, "Dominio do seu site (ex. teste.tempsite.ws)" )
169
+ config.input( :usuario, "Seu usuario de hospedagem" )
170
+ mysqlcfg.input( :db, "Nome do seu banco mysql (enter para '#{config.usuario}')", config.usuario )
171
+ mysqlcfg.input( :user, "Seu usuario de mysql (enter para #{mysqlcfg.db})", mysqlcfg.db )
172
+ mysqlcfg.input( :pass, "Sua senha de mysql" )
173
+ mysqlcfg.input( :host, "Seu servidor mysql (ex. mysqlxxxx.locaweb.com.br)" )
174
+ if config.mode == 'git'
175
+ config.input( :branch, "Git branch local (enter para 'master')", 'master' )
176
+ config.input( :remote_repo, "Nome do repositorio remoto (enter para 'locaweb')", 'locaweb' )
177
+ config.remote_git = "#{config.usuario}@#{config.dominio}:~/repo/#{config.app_name}.git"
178
+ end
179
+
180
+ # forca rodar capistrano
181
+ unless File.exists?("#{config.local_path}/Capfile")
182
+ puts "- Executando Capistrano no seu projeto ..."
183
+ begin
184
+ `capify .`
185
+ rescue Exception => e
186
+ puts <<-STR
187
+ ERRO: Voce provavelmente nao tem Capistrano instalado
188
+ Rode: sudo gem install capistrano
189
+
190
+ STR
191
+ end
192
+ end
193
+
194
+ if config.mode == 'git'
195
+ begin
196
+ FileUtils.copy_file("#{config.bin_path}/../templates/.gitignore",
197
+ "#{config.local_path}/.gitignore") unless File.exists?("#{config.local_path}/.gitignore")
198
+ rescue
199
+ puts "Error copying file #{config.bin_path}/../templates/.gitignore"
200
+ end
201
+ end
202
+
203
+ begin
204
+ FileUtils.copy_file("#{config.bin_path}/../templates/locaweb_backup.rb",
205
+ "#{config.local_path}/config/locaweb_backup.rb") unless File.exists?("#{config.local_path}/config/locaweb_backup.rb")
206
+ rescue
207
+ puts "Error copying file #{config.bin_path}/../templates/locaweb_backup.rb"
208
+ end
209
+
210
+ begin
211
+ FileUtils.copy_file("#{config.bin_path}/../templates/ssh_helper.rb",
212
+ "#{config.local_path}/config/ssh_helper.rb") unless File.exists?("#{config.local_path}/config/ssh_helper.rb")
213
+ rescue
214
+ puts "Error copying file #{config.bin_path}/../templates/ssh_helper.rb"
215
+ end
216
+
217
+ File.open("#{config.local_path}/config/deploy.rb", 'w') do |out|
218
+ erb = ERB.new(File.read("#{config.bin_path}/../templates/deploy.rb.erb"))
219
+ buffer = erb.result(config.send(:binding))
220
+ erb = ERB.new(File.read("#{config.bin_path}/../templates/deploy.common.rb.erb"))
221
+ buffer << erb.result(config.send(:binding))
222
+ out.puts buffer
223
+ end
224
+
225
+ File.open("#{config.local_path}/config/database.locaweb.yml", 'w') do |out|
226
+ erb = ERB.new(File.read("#{config.bin_path}/../templates/database.locaweb.yml.erb"))
227
+ out.puts erb.result(mysqlcfg.send(:binding))
228
+ end
229
+
230
+ puts <<-STR
231
+
232
+ # Parabens, voce terminou de configurar sua aplicacao Rails!
233
+ # Execute apenas uma vez 'cap deploy:setup' para configurar os
234
+ diretorios remotamente na sua hospedagem.
235
+ # Em seguida execute 'cap deploy' para transportar sua aplicacao
236
+ para a hospedagem. Sempre que quiser atualizar sua aplicacao
237
+ no servidor apenas execute novamente 'cap deploy'
238
+
239
+ [finalizado!]
240
+ STR
@@ -0,0 +1 @@
1
+ @ruby "C:/ruby/bin/locarails" %*
@@ -0,0 +1,4 @@
1
+ module Locarails
2
+ end
3
+
4
+ require 'locarails/version'
@@ -0,0 +1,24 @@
1
+ module Capistrano
2
+ module Deploy
3
+ module Strategy
4
+ class Base
5
+ protected
6
+ # A wrapper for Kernel#system that logs the command being executed.
7
+ def system(*args)
8
+ cmd = args.join(' ')
9
+ if RUBY_PLATFORM =~ /win32/
10
+ cmd.gsub!('/','\\') # Replace / with \\
11
+ cmd.gsub!(/^cd /,'cd /D ') # Replace cd with cd /D
12
+ cmd.gsub!(/&& cd /,'&& cd /D ') # Replace cd with cd /D
13
+ cmd.gsub!('%%', '/') # Avoid windows command line parameters to be erroneously replaced by backslashes
14
+ logger.trace "executing locally: #{cmd}"
15
+ super(cmd)
16
+ else
17
+ logger.trace "executing locally: #{cmd}"
18
+ super
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,73 @@
1
+ class Capistrano::Deploy::Strategy::Copy
2
+ # Obtains a copy of the source code locally (via the #command method),
3
+ # compresses it to a single file, copies that file to all target
4
+ # servers, and uncompresses it on each of them into the deployment
5
+ # directory.
6
+ def deploy!
7
+ if copy_cache
8
+ if File.exists?(copy_cache)
9
+ logger.debug "refreshing local cache to revision #{revision} at #{copy_cache}"
10
+ system(source.sync(revision, copy_cache))
11
+ else
12
+ logger.debug "preparing local cache at #{copy_cache}"
13
+ system(source.checkout(revision, copy_cache))
14
+ end
15
+
16
+ logger.debug "copying cache to deployment staging area #{destination}"
17
+ Dir.chdir(copy_cache) do
18
+ FileUtils.mkdir_p(destination)
19
+ queue = Dir.glob("*", File::FNM_DOTMATCH)
20
+ while queue.any?
21
+ item = queue.shift
22
+ name = File.basename(item)
23
+
24
+ next if name == "." || name == ".."
25
+ next if copy_exclude.any? { |pattern| File.fnmatch(pattern, item) }
26
+
27
+ if File.symlink?(item)
28
+ FileUtils.ln_s(File.readlink(File.join(copy_cache, item)), File.join(destination, item))
29
+ elsif File.directory?(item)
30
+ queue += Dir.glob("#{item}/*", File::FNM_DOTMATCH)
31
+ FileUtils.mkdir(File.join(destination, item))
32
+ else
33
+ FileUtils.ln(File.join(copy_cache, item), File.join(destination, item))
34
+ end
35
+ end
36
+ end
37
+ else
38
+ logger.debug "getting (via #{copy_strategy}) revision #{revision} to #{destination}"
39
+ system(command)
40
+
41
+ if copy_exclude.any?
42
+ logger.debug "processing exclusions..."
43
+ if copy_exclude.any?
44
+ copy_exclude.each do |pattern|
45
+ delete_list = Dir.glob(File.join(destination, pattern), File::FNM_DOTMATCH)
46
+ # avoid the /.. trap that deletes the parent directories
47
+ delete_list.delete_if { |dir| dir =~ /\/\.\.$/ }
48
+ FileUtils.rm_rf(delete_list.compact)
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ File.open(File.join(destination, "REVISION"), "w") { |f| f.puts(revision) }
55
+
56
+ logger.trace "compressing #{destination} to #{filename}"
57
+ # if it is Windows, force gzip using the pure Ruby minitar library
58
+ if Capistrano::Deploy::LocalDependency.on_windows?
59
+ require 'zlib'
60
+ require 'archive/tar/minitar'
61
+ Dir.chdir(tmpdir) { Archive::Tar::Minitar.pack(File.basename(destination), Zlib::GzipWriter.new(File.open(File.basename(filename), 'wb'))) }
62
+ configuration[:copy_compression] = :gzip
63
+ else
64
+ Dir.chdir(tmpdir) { system(compress(File.basename(destination), File.basename(filename)).join(" ")) }
65
+ end
66
+
67
+ upload(filename, remote_filename)
68
+ run "cd #{configuration[:releases_path]} && #{decompress(remote_filename).join(" ")} && rm #{remote_filename}"
69
+ ensure
70
+ FileUtils.rm filename rescue nil
71
+ FileUtils.rm_rf destination rescue nil
72
+ end
73
+ end
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ unless Gem.source_index.find_name('capistrano').select { |g| g.version.to_s =~ /^2\.5/ }.empty?
3
+ puts "Loading temporary fixes for Capistrano 2.5.x"
4
+ require 'capistrano'
5
+ require 'capistrano/recipes/deploy/dependencies'
6
+ require 'capistrano/recipes/deploy/strategy/base'
7
+ require 'capistrano/recipes/deploy/strategy/copy'
8
+ require 'capistrano/recipes/deploy/scm/git'
9
+ require 'capistrano/recipes/deploy/scm/none'
10
+ require 'locarails/base'
11
+ require 'locarails/copy'
12
+ require 'locarails/git'
13
+ require 'locarails/none'
14
+ end
@@ -0,0 +1,39 @@
1
+ class Capistrano::Deploy::SCM::Git
2
+ alias :checkout_old :checkout
3
+ def checkout(revision, destination)
4
+ sub_wrapper(:checkout_old, revision, destination)
5
+ end
6
+
7
+ alias :sync_old :sync
8
+ def sync(revision, destination)
9
+ sub_wrapper(:sync_old, revision, destination)
10
+ end
11
+
12
+ def sub_wrapper(method, revision, destination)
13
+ execute = send(method, revision, destination) # execute original method
14
+ # filter the git URL to force it to a local file:// URL
15
+ execute.collect do |line|
16
+ if line.include?(configuration[:repository])
17
+ line.sub(configuration[:repository], remote_repository)
18
+ else
19
+ line
20
+ end
21
+ end
22
+ end
23
+
24
+ # force the remote git commands to fetch from the local filesystem instead
25
+ # making a round-trip to itself through ssh
26
+ def remote_repository
27
+ url = "#{configuration[:user]}@#{configuration[:domain]}:"
28
+ @remote_repository ||= if configuration[:repository].include?(url)
29
+ tmp = configuration[:repository].sub(url, "file://")
30
+ if tmp.include?("~")
31
+ tmp.sub!("~", "/home/#{configuration[:user]}")
32
+ end
33
+ tmp
34
+ else
35
+ configuration[:repository]
36
+ end
37
+ @remote_repository
38
+ end
39
+ end
@@ -0,0 +1,10 @@
1
+ class Capistrano::Deploy::SCM::None
2
+ # Simply does a copy from the :repository directory to the
3
+ # :destination directory.
4
+ # fix: avoid xcopy parameters to be erroneously replaced by backslashes
5
+ def checkout(revision, destination)
6
+ !Capistrano::Deploy::LocalDependency.on_windows? ? "cp -R #{repository} #{destination}" : "xcopy #{repository} \"#{destination}\" %%S%%I%%Y%%Q%%E"
7
+ end
8
+
9
+ alias_method :export, :checkout
10
+ end
@@ -0,0 +1,9 @@
1
+ module Locarails
2
+ module VERSION #:nodoc:
3
+ MAJOR = 1
4
+ MINOR = 2
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,43 @@
1
+ locarails_gemspec = Gem::Specification.new do |s|
2
+ s.name = "locarails"
3
+ s.version = Locarails::VERSION::STRING
4
+ s.homepage = "http://www.locaweb.com.br/rails"
5
+ s.summary = "Configuracao de Capistrano automatica para hospedagens Linux Locaweb."
6
+ s.authors = ["Fabio Akita"]
7
+ s.date = %q{Time.now.strftime("%Y/%d/%m")}
8
+ s.default_executable = "locarails"
9
+ s.description = "A maneira mais simples para instalar aplicacoes Rails na hospedagem Linux da Locaweb."
10
+ s.email = "fabio.akita@locaweb.com.br"
11
+ s.executables = ["locarails"]
12
+ s.files = Dir.glob("{bin,lib,templates,tasks}/**/*") + ['templates/.gitignore']
13
+ s.has_rdoc = true
14
+ s.require_paths = ["lib"]
15
+
16
+ s.add_runtime_dependency("capistrano", [">= 2.0.0"])
17
+ s.add_runtime_dependency("highline", [">= 0"])
18
+ s.add_runtime_dependency("archive-tar-minitar", [">= 0.5.2"])
19
+ end
20
+
21
+
22
+ Rake::GemPackageTask.new(locarails_gemspec) do |pkg|
23
+ pkg.gem_spec = locarails_gemspec
24
+ end
25
+
26
+ namespace :gem do
27
+ namespace :spec do
28
+ desc "Update locarails.gemspec"
29
+ task :generate do
30
+ File.open("locarails.gemspec", "w") do |f|
31
+ f.puts(locarails_gemspec.to_ruby)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ desc "Generate package and install"
38
+ task :install => :package do
39
+ sh %{sudo gem install --local pkg/locarails-#{Locarails::VERSION}}
40
+ end
41
+
42
+ desc "Remove all generated artifacts"
43
+ task :clean => :clobber_package
@@ -0,0 +1,22 @@
1
+ log/*.log
2
+ log/*.out
3
+ log/*.pid
4
+ tmp/**/*
5
+ .DS_Store
6
+ db/schema.rb
7
+ db/schema.sql
8
+ db/*.sqlite3*
9
+ config/database.yml
10
+ config/database.locaweb.yml
11
+ public/photos/*
12
+ public/upload/*
13
+ public/assets/*
14
+ .project
15
+ .#*
16
+ tmp/.*
17
+ \#*
18
+ *~
19
+ vendor/**/**/doc/*
20
+ rsa_key*
21
+ coverage/
22
+ coverage
@@ -0,0 +1,8 @@
1
+ production:
2
+ adapter: mysql
3
+ encoding: utf8
4
+ database: <%= mysqlcfg.db %>
5
+ username: <%= mysqlcfg.user %>
6
+ password: <%= mysqlcfg.pass %>
7
+ host: <%= mysqlcfg.host %>
8
+ pool: 5
@@ -0,0 +1,136 @@
1
+ # =============================================================================
2
+ # TAREFAS - NAO MEXER A MENOS QUE SAIBA O QUE ESTA FAZENDO
3
+ # =============================================================================
4
+ desc "Garante que o database.yml foi corretamente configurado"
5
+ task :before_symlink do
6
+ on_rollback {}
7
+ run "test -d #{release_path}/tmp || mkdir -m 755 #{release_path}/tmp"
8
+ run "test -d #{release_path}/db || mkdir -m 755 #{release_path}/db"
9
+ run "cp #{deploy_to}/etc/database.yml #{release_path}/config/database.yml"
10
+ run "cd #{release_path} && rake db:migrate RAILS_ENV=production"
11
+ end
12
+
13
+ desc "Garante que as configuracoes estao adequadas"
14
+ task :before_setup do
15
+ ts = Time.now.strftime("%y%m%d%H%M%S")
16
+ <% if config.mode == 'git' %>
17
+ # git folder
18
+ run "test -d #{git_repo} || mkdir -p -m 755 #{git_repo}"
19
+ run "test -d #{git_repo}/.git || cd #{git_repo} && git init"
20
+ git_config = File.join(File.dirname(__FILE__), "../.git/config")
21
+
22
+ has_git = false
23
+ if File.exists?(git_config)
24
+ `git remote rm #{remote_repo}` if File.read(git_config) =~ /\[remote\s+\"#{remote_repo}\"\]/
25
+ `git remote add #{remote_repo} #{repository}`
26
+ output = `git branch`.strip
27
+ `git checkout master && git checkout -b #{branch}` if output !~ /#{branch}/
28
+ `git checkout #{branch}` if output !~ /^\*\s+#{branch}/
29
+ `git push #{remote_repo} #{branch}`
30
+ has_git = true
31
+ end
32
+ <% end %>
33
+
34
+ run "test -d /home/#{user}/rails_app || mkdir -m 755 /home/#{user}/rails_app"
35
+ run "if [ -d #{deploy_to} ]; then mv #{deploy_to} #{deploy_to}-#{ts}.old ; fi"
36
+ run "test -d #{deploy_to} || mkdir -m 755 #{deploy_to}"
37
+ run "test -d #{deploy_to}/etc || mkdir -m 755 #{deploy_to}/etc"
38
+ run "if [ -d #{site_path} ]; then mv #{site_path} #{site_path}-#{ts}.old ; fi"
39
+ run "if [ -h #{site_path} ]; then mv #{site_path} #{site_path}-#{ts}.old ; fi"
40
+ run "ln -s #{deploy_to}/current/public #{public_html}/#{application}"
41
+ upload File.join(File.dirname(__FILE__), "database.locaweb.yml"), "#{deploy_to}/etc/database.yml"
42
+ upload File.join(File.dirname(__FILE__), "locaweb_backup.rb"), "#{deploy_to}/etc/locaweb_backup.rb"
43
+ upload File.join(File.dirname(__FILE__), "ssh_helper.rb"), "#{deploy_to}/etc/ssh_helper.rb"
44
+
45
+ <% if config.mode == 'git' %>
46
+ # ssh keygen
47
+ run "test -f ~/.ssh/id_rsa || ruby #{deploy_to}/etc/ssh_helper.rb /home/#{user}/.ssh/id_rsa #{domain} #{user}"
48
+
49
+ unless has_git
50
+ 2.times { puts "" }
51
+ puts "==============================================================="
52
+ puts "Rode os seguintes comandos depois de criar seu repositorio Git:"
53
+ puts ""
54
+ puts " git remote add #{remote_repo} #{repository}"
55
+ puts " git push #{remote_repo} #{branch}"
56
+ puts "==============================================================="
57
+ 2.times { puts "" }
58
+ end
59
+ <% end %>
60
+ end
61
+
62
+ desc "Prepare the production database before migration"
63
+ task :before_cold do
64
+ end
65
+
66
+ namespace :deploy do
67
+ desc "Pede restart ao servidor Passenger"
68
+ task :restart, :roles => :app do
69
+ run "chmod -R 755 #{release_path}"
70
+ run "touch #{deploy_to}/current/tmp/restart.txt"
71
+ end
72
+ end
73
+
74
+ [:start, :stop].each do |t|
75
+ desc "A tarefa #{t} nao eh necessaria num ambiente com Passenger"
76
+ task t, :roles => :app do ; end
77
+ end
78
+
79
+ namespace :log do
80
+ desc "tail production log files"
81
+ task :tail, :roles => :app do
82
+ run "tail -f #{shared_path}/log/production.log" do |channel, stream, data|
83
+ puts # para uma linha extra
84
+ puts "#{channel[:host]}: #{data}"
85
+ break if stream == :err
86
+ end
87
+ end
88
+ end
89
+
90
+ namespace :db do
91
+ desc "Faz o backup remoto e download do banco de dados MySQL"
92
+ task :backup, :roles => :db do
93
+ backup_rb ||= "#{deploy_to}/etc/locaweb_backup.rb"
94
+ run "if [ -f #{backup_rb} ]; then ruby #{backup_rb} backup #{deploy_to} ; fi"
95
+ get "#{deploy_to}/etc/dump.tar.gz", "dump.tar.gz"
96
+ run "rm #{deploy_to}/etc/dump.tar.gz"
97
+ end
98
+
99
+ desc "Faz o upload e o restore remoto do banco de dados MySQL"
100
+ task :restore, :roles => :db do
101
+ unless File.exists?("dump.tar.gz")
102
+ puts "Backup dump.tar.gz nao encontrado"
103
+ exit 0
104
+ end
105
+ backup_rb ||= "#{deploy_to}/etc/locaweb_backup.rb"
106
+ upload "dump.tar.gz", "#{deploy_to}/etc/dump.tar.gz"
107
+ run "if [ -f #{backup_rb} ]; then ruby #{backup_rb} restore #{deploy_to} ; fi"
108
+ end
109
+
110
+ desc "Apaga todas as tabelas do banco de dados [CUIDADO! OPERACAO SEM VOLTA!]"
111
+ task :drop_all, :roles => :db do
112
+ backup_rb ||= "#{deploy_to}/etc/locaweb_backup.rb"
113
+ run "if [ -f #{backup_rb} ]; then ruby #{backup_rb} drop_all #{deploy_to} ; fi"
114
+ end
115
+ end
116
+
117
+ namespace :ssh do
118
+ desc "Faz upload da sua chave publica"
119
+ task :upload_key, :roles => :app do
120
+ public_key_path = File.expand_path("~/.ssh/id_rsa.pub")
121
+ unless File.exists?(public_key_path)
122
+ puts %{
123
+ Chave publica nao encontrada em #{public_key_path}
124
+ Crie sua chave - sem passphrase - com o comando:
125
+ ssh_keygen -t rsa
126
+ }
127
+ exit 0
128
+ end
129
+ ssh_path = "/home/#{user}/.ssh"
130
+ run "test -d #{ssh_path} || mkdir -m 755 #{ssh_path}"
131
+ upload public_key_path, "#{ssh_path}/../id_rsa.pub"
132
+ run "test -f #{ssh_path}/authorized_keys || touch #{ssh_path}/authorized_keys"
133
+ run "cat #{ssh_path}/../id_rsa.pub >> #{ssh_path}/authorized_keys"
134
+ run "chmod 755 #{ssh_path}/authorized_keys"
135
+ end
136
+ end
@@ -0,0 +1,77 @@
1
+ # =============================================================================
2
+ # Receita de Capistrano 2.x para hospedagem compartilhada Linux
3
+ # utilizando estratégia de cópia sem servidor de versionamento
4
+ # =============================================================================
5
+ #
6
+ # 1. Esta receita é executada na sua maquina local e nao na hospedagem remota
7
+ #
8
+ # 2. O Locarails depende da gem Capistrano
9
+ #
10
+ # 3. A estrategia de deployment padrao eh Copy, que comprime seu projeto e envia
11
+ # para o servidor via SCP, e la eh descomprimido. Esta opcao funciona em
12
+ # qualquer sistema operacional sem mais nenhuma dependencia, incluindo
13
+ # Windows
14
+ #
15
+ # 4. A opcao -m git ativa a receita via Git que eh um repositorio descentralizado
16
+ # muito eficiente e que garante um deployment ainda mais rapido. Eh necessario
17
+ # que seu projeto local esteja em git e voce precisa do Git instalado na sua
18
+ # maquina
19
+ #
20
+ # 5. Ainda nao existe suporte a Subversion
21
+ #
22
+ #
23
+ # Autor: Fabio Akita
24
+ # E-mail: fabio.akita@locaweb.com.br
25
+ # Locaweb Serviços de Internet S/A
26
+ # Todos os direitos reservados
27
+
28
+ # correcao temporaria para capistrano 2.5.0
29
+ require 'locarails/fix'
30
+
31
+ # =============================================================================
32
+ # CONFIGURE OS VALORES DE ACORDO COM SUA HOSPEDAGEM
33
+ # =============================================================================
34
+ set :user, "<%= config.usuario %>"
35
+ set :domain, "<%= config.dominio %>"
36
+ set :application, "<%= config.app_name %>"
37
+ <% if config.mode == 'git' %>
38
+ set :repository, "<%= config.remote_git %>"
39
+ set :remote_repo, '<%= config.remote_repo %>'
40
+ set :branch, '<%= config.branch %>'
41
+ set :git_repo, "/home/#{user}/repo/#{application}.git"
42
+ <% else %>
43
+ set :repository, "<%= config.local_path %>"
44
+ <% end %>
45
+ <% if config.ssh_key_path %>
46
+ ssh_options[:keys] = File.expand_path("<%= config.ssh_key_path %>") # apenas descomente se tiver chave
47
+ <% end %>
48
+
49
+ # =============================================================================
50
+ # NAO MEXER DAQUI PARA BAIXO
51
+ # =============================================================================
52
+ role :web, domain
53
+ role :app, domain
54
+ role :db, domain
55
+
56
+ set :deploy_to, "/home/#{user}/rails_app/#{application}"
57
+ set :public_html, "/home/#{user}/public_html"
58
+ set :site_path, "#{public_html}/#{application}"
59
+ set :runner, nil
60
+ set :use_sudo, false
61
+ set :no_release, true
62
+
63
+ <% if config.mode == 'git' %>
64
+ set :scm, :git
65
+ set :deploy_via, :remote_cache
66
+ set :git_shallow_clone, 1
67
+ set :remote, user
68
+ set :scm_verbose, true
69
+ <% else %>
70
+ set :scm, :none
71
+ set :deploy_via, :copy
72
+ <% end %>
73
+ set :copy_exclude, %w(.git/* .svn/* log/* tmp/* .gitignore)
74
+ set :keep_releases, 5
75
+
76
+ ssh_options[:username] = user
77
+ ssh_options[:paranoid] = false
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby -wKU
2
+ require 'yaml'
3
+ require 'erb'
4
+
5
+ operation, deploy_to = ARGV
6
+ cfg = YAML::load(ERB.new(IO.read("#{deploy_to}/etc/database.yml")).result)
7
+ exit 0 unless cfg['production'] # sai se nao encontrar o arquivo de banco
8
+ prd = cfg['production']
9
+ mysql_opts = "-u #{prd['username']} -p#{prd['password']} -h #{prd['host']} #{prd['database']}"
10
+ mysql_opts_no_data = "-u #{prd['username']} -p#{prd['password']} -h #{prd['host']} --add-drop-table --no-data #{prd['database']}"
11
+
12
+ commands = []
13
+
14
+ case operation
15
+ when 'backup'
16
+ commands << "mysqldump #{mysql_opts} > #{deploy_to}/etc/dump.sql"
17
+ commands << "cd #{deploy_to}/etc && tar cvfz dump.tar.gz dump.sql"
18
+ commands << "rm #{deploy_to}/etc/dump.sql"
19
+ when 'restore'
20
+ commands << "cd #{deploy_to}/etc && if [ -f dump.tar.gz ]; then tar xvfz dump.tar.gz dump.sql ; fi"
21
+ commands << "if [ -f #{deploy_to}/etc/dump.sql ]; then mysql -u #{mysql_opts} < #{deploy_to}/etc/dump.sql && rm #{deploy_to}/etc/dump.sql ; fi"
22
+ when 'drop_all'
23
+ commands << "mysqldump #{mysql_opts_no_data} | grep ^DROP | mysql #{mysql_opts}"
24
+ end
25
+
26
+ commands.each do |cmd|
27
+ puts "executando: #{cmd.gsub(prd['password'], '*****')}"
28
+ `#{cmd}`
29
+ end
30
+ puts "operacao #{operation} finalizada."
@@ -0,0 +1,319 @@
1
+ require 'rubygems'
2
+ gem "net-ssh", ">= 1.1.3"
3
+ require 'base64'
4
+ require 'net/ssh'
5
+
6
+ #--
7
+ # =============================================================================
8
+ # Copyright (c) 2004,2005 Jamis Buck (jamis@37signals.com)
9
+ # All rights reserved.
10
+ #
11
+ # This source file is distributed as part of the Net::SSH Secure Shell Client
12
+ # library for Ruby. This file (and the library as a whole) may be used only as
13
+ # allowed by either the BSD license, or the Ruby license (or, by association
14
+ # with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SSH
15
+ # distribution for the texts of these licenses.
16
+ # -----------------------------------------------------------------------------
17
+ # net-ssh website : http://net-ssh.rubyforge.org
18
+ # project website: http://rubyforge.org/projects/net-ssh
19
+ # =============================================================================
20
+ #++
21
+
22
+ module Net
23
+ module SSH
24
+
25
+ module Util
26
+
27
+ # The abstract ancestor module of both ReaderBufferImpl and
28
+ # WriterBufferImpl. It defines the common interface for both submodules.
29
+ module BufferBase
30
+
31
+ # exposes the content of the buffer
32
+ attr_reader :content
33
+
34
+ # the length of the buffer's content.
35
+ def length
36
+ @content.length
37
+ end
38
+
39
+ # returns a copy of the buffer's content.
40
+ def to_s
41
+ ( @content || "" ).dup
42
+ end
43
+
44
+ # Compares the contents of the two buffers.
45
+ def ==( buffer )
46
+ to_s == buffer.to_s
47
+ end
48
+
49
+ # Resets the buffer, making it empty.
50
+ def clear!
51
+ @content = ""
52
+ end
53
+
54
+ def init_BufferBase( content="" )
55
+ @content = content
56
+ end
57
+ private :init_BufferBase
58
+
59
+ end
60
+
61
+ # A convenience module for representing a string of encoded data. It
62
+ # provides an interface for easily reading and decoding the buffer.
63
+ module ReaderBufferImpl
64
+
65
+ # the current position of the pointer in the buffer
66
+ attr_reader :position
67
+
68
+ # used by derived modules and classes to perform any
69
+ # reader-buffer-specific initialization.
70
+ def init_ReaderBufferImpl
71
+ @position = 0
72
+ end
73
+ private :init_ReaderBufferImpl
74
+
75
+ # Appends the given text to the end of the buffer.
76
+ def append( text )
77
+ @content << text
78
+ end
79
+
80
+ # Returns all text from the current pointer to the end of the buffer as
81
+ # a new buffer as the same class as the receiver.
82
+ def remainder_as_buffer
83
+ self.class.new( @content[ @position..-1 ] )
84
+ end
85
+
86
+ # Reads +count+ bytes from the buffer. If +count+ is +nil+, this will
87
+ # return all remaining text in the buffer. This method will increment
88
+ # the pointer.
89
+ def read( count = nil )
90
+ count = length - @position unless count
91
+ return nil if @position + count > length
92
+
93
+ @position += count
94
+ @content[ @position-count, count ]
95
+ end
96
+
97
+ # Return the next 8 bytes as a 64-bit integer (in network byte order).
98
+ def read_int64
99
+ hi = read_long
100
+ lo = read_long
101
+ return ( hi << 32 ) + lo
102
+ end
103
+
104
+ # Return the next four bytes as a long integer (in network byte order).
105
+ def read_long
106
+ b = read( 4 ) or return nil
107
+ b.unpack( "N" ).first
108
+ end
109
+
110
+ # Read the next two bytes as a short integer (in network byte order).
111
+ def read_short
112
+ b = read( 2 ) or return nil
113
+ b.unpack( "n" ).first
114
+ end
115
+
116
+ # Read and return the next byte in the buffer.
117
+ def read_byte
118
+ b = read( 1 ) or return nil
119
+ b[0]
120
+ end
121
+
122
+ # Read and return an SSH2-encoded string. The string starts with a long
123
+ # integer that describes the number of bytes remaining in the string.
124
+ def read_string
125
+ length = read_long or return nil
126
+ read( length )
127
+ end
128
+
129
+ # Read a single byte and convert it into a boolean, using 'C' rules
130
+ # (i.e., zero is false, non-zero is true).
131
+ def read_bool
132
+ b = read( 1 ) or return nil
133
+ b[0] != 0
134
+ end
135
+
136
+ # Resets the pointer to the start of the buffer.
137
+ def reset!
138
+ @position = 0
139
+ end
140
+
141
+ # Returns true if the pointer is at the end of the buffer.
142
+ def eof?
143
+ @position >= length
144
+ end
145
+
146
+ # Resets the buffer, making it empty.
147
+ def clear!
148
+ @content = ""
149
+ @position = 0
150
+ end
151
+
152
+ end # ReaderBufferImpl
153
+
154
+ # A convenience module for writing a string of encoded data. It provides
155
+ # an interface for easily writing and encoding data.
156
+ module WriterBufferImpl
157
+
158
+ def init_WriterBufferImpl
159
+ # nothing
160
+ end
161
+ private :init_WriterBufferImpl
162
+
163
+ # Writes the given data literally into the string.
164
+ def write( *data )
165
+ @content << data.join
166
+ end
167
+
168
+ # Writes each argument to the buffer as a network-byte-order-encoded
169
+ # 64-bit integer (8 bytes).
170
+ def write_int64( *n )
171
+ n.each do |i|
172
+ hi = ( i >> 32 ) & 0xFFFFFFFF
173
+ lo = i & 0xFFFFFFFF
174
+ @content << [ hi, lo ].pack( "N2" )
175
+ end
176
+ end
177
+
178
+ # Writes each argument to the buffer as a network-byte-order-encoded
179
+ # long (4-byte) integer.
180
+ def write_long( *n )
181
+ @content << n.pack( "N*" )
182
+ end
183
+
184
+ # Writes each argument to the buffer as a network-byte-order-encoded
185
+ # short (2-byte) integer.
186
+ def write_short( *n )
187
+ @content << n.pack( "n*" )
188
+ end
189
+
190
+ # Writes each argument to the buffer as a byte.
191
+ def write_byte( *n )
192
+ @content << n.map { |c| c.chr }.join
193
+ end
194
+
195
+ # Writes each argument to the buffer as an SSH2-encoded string. Each
196
+ # string is prefixed by its length, encoded as a 4-byte long integer.
197
+ def write_string( *text )
198
+ text.each do |string|
199
+ write_long( string.length )
200
+ write( string )
201
+ end
202
+ end
203
+
204
+ # Writes each argument to the buffer as a (C-style) boolean, with 1
205
+ # meaning true, and 0 meaning false.
206
+ def write_bool( *b )
207
+ @content << b.map { |v| ( v ? 1 : 0 ).chr }.join
208
+ end
209
+
210
+ # Writes each argument to the buffer as a bignum (SSH2-style). No
211
+ # checking is done to ensure that the arguments are, in fact, bignums.
212
+ def write_bignum( *n )
213
+ @content << n.map { |b| b.to_ssh }.join
214
+ end
215
+
216
+ # Writes the given arguments to the buffer as SSH2-encoded keys.
217
+ def write_key( *key )
218
+ key.each do |k|
219
+ write_string( k.ssh_type )
220
+
221
+ case k.ssh_type
222
+ when "ssh-dss"
223
+ write_bignum( k.p )
224
+ write_bignum( k.q )
225
+ write_bignum( k.g )
226
+ write_bignum( k.pub_key )
227
+
228
+ when "ssh-rsa"
229
+ write_bignum( k.e )
230
+ write_bignum( k.n )
231
+
232
+ else
233
+ raise NotImplementedError,
234
+ "unsupported key type '#{k.ssh_type}'"
235
+ end
236
+ end
237
+ end
238
+
239
+ end # class WriterBufferImpl
240
+
241
+ # A convenience class for a read-only buffer.
242
+ class ReaderBuffer
243
+ include BufferBase
244
+ include ReaderBufferImpl
245
+
246
+ def initialize( content )
247
+ init_BufferBase( content )
248
+ init_ReaderBufferImpl
249
+ end
250
+ end
251
+
252
+ # A convenience class for a write-only buffer.
253
+ class WriterBuffer
254
+ include BufferBase
255
+ include WriterBufferImpl
256
+
257
+ def initialize( content="" )
258
+ init_BufferBase( content )
259
+ init_WriterBufferImpl
260
+ end
261
+ end
262
+
263
+ # A convenience class for a read/write buffer.
264
+ class Buffer
265
+ include BufferBase
266
+ include ReaderBufferImpl
267
+ include WriterBufferImpl
268
+
269
+ def initialize( content="" )
270
+ init_BufferBase( content )
271
+ init_ReaderBufferImpl
272
+ init_WriterBufferImpl
273
+ end
274
+ end
275
+
276
+ end # module Util
277
+
278
+ end # module SSH
279
+ end # module Net
280
+
281
+ class SSHHelper
282
+ def self.generate_keys(filename)
283
+ authorized_file = "#{File.dirname(filename)}/authorized_keys"
284
+
285
+ private_key = OpenSSL::PKey::RSA.new(2048)
286
+ public_pem = export_ssh_pubkey( private_key )
287
+
288
+ File.delete( filename ) if File.exists?( filename )
289
+ File.open( filename, "w" ) { |file| file.write private_key.export }
290
+ File.delete( "#{filename}.pub" ) if File.exists?("#{filename}.pub")
291
+ File.open( "#{filename}.pub", "w" ) { |file| file.write public_pem }
292
+ File.open( authorized_file, 'w') { |file| file.write public_pem + "\n"}
293
+
294
+ FileUtils.chmod 0755, authorized_file
295
+ FileUtils.chmod 0600, filename
296
+ end
297
+
298
+ def self.test_connection(hostname, username)
299
+ # will create known_host
300
+ Net::SSH.start(hostname, username) { |ssh| puts ssh.exec!('hostname') }
301
+ end
302
+
303
+ private
304
+ def self.export_ssh_pubkey( key )
305
+ s = key.ssh_type + " "
306
+
307
+ writer = Net::SSH::Util::WriterBuffer.new
308
+ writer.write_key key
309
+ s << Base64.encode64( writer.to_s ).strip.gsub( /[\n\r\t ]/, "" )
310
+ s << " #{ENV['USER']}@#{ENV['HOSTNAME']}"
311
+
312
+ s
313
+ end
314
+ end
315
+
316
+ if ARGV && ARGV.size == 3
317
+ SSHHelper.generate_keys(ARGV[0])
318
+ SSHHelper.test_connection(ARGV[1], ARGV[2])
319
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: locarails
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Fabio Akita
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-22 00:00:00 -03:00
13
+ default_executable: locarails
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: capistrano
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.0.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: highline
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: archive-tar-minitar
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.5.2
44
+ version:
45
+ description: A maneira mais simples para instalar aplicacoes Rails na hospedagem Linux da Locaweb.
46
+ email: fabio.akita@locaweb.com.br
47
+ executables:
48
+ - locarails
49
+ extensions: []
50
+
51
+ extra_rdoc_files: []
52
+
53
+ files:
54
+ - bin/locarails
55
+ - bin/locarails.cmd
56
+ - lib/locarails/base.rb
57
+ - lib/locarails/copy.rb
58
+ - lib/locarails/fix.rb
59
+ - lib/locarails/git.rb
60
+ - lib/locarails/none.rb
61
+ - lib/locarails/version.rb
62
+ - lib/locarails.rb
63
+ - templates/database.locaweb.yml.erb
64
+ - templates/deploy.common.rb.erb
65
+ - templates/deploy.rb.erb
66
+ - templates/locaweb_backup.rb
67
+ - templates/ssh_helper.rb
68
+ - tasks/gems.rake
69
+ - templates/.gitignore
70
+ has_rdoc: true
71
+ homepage: http://www.locaweb.com.br/rails
72
+ licenses: []
73
+
74
+ post_install_message:
75
+ rdoc_options: []
76
+
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: "0"
84
+ version:
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ version:
91
+ requirements: []
92
+
93
+ rubyforge_project:
94
+ rubygems_version: 1.3.5
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: Configuracao de Capistrano automatica para hospedagens Linux Locaweb.
98
+ test_files: []
99
+