-
-
Save toekneestuck/2895972 to your computer and use it in GitHub Desktop.
Rake tasks for deploying a web app via rsync, and comparing local / remote file changes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CONFIG = { | |
## -- Rsync Deploy config -- ## | |
# Be sure you have setup public / private key authentication | |
:ssh_host => "user@hostname", # The hostname can be an alias in ~/.ssh/config | |
:ssh_port => nil, # Default - use ~/.ssh/config | |
:document_root => "/var/www", # Remote document root | |
:rsync_delete => true, # Whether or not to delete remote files | |
:deploy_default => "rsync", # Not used | |
:restart_apache => nil, # Remote command to restart apache | |
## -- Misc Configs -- ## | |
:site_dir => "." # Local site directory (sync this folder to the remote document_root) | |
} | |
## -- Rake Tasks -- ## | |
desc "Deploy website via rsync (e.g. rake deploy [path=...] [options=<extra rsync options>])" | |
task :deploy do | |
# Run commands | |
puts "## Deploying website via Rsync" | |
puts "-----------\nCommand: #{rsync_command '--dry-run'}\n-----------" | |
system(rsync_command '--dry-run') | |
# Prompt for continuance | |
puts | |
proceed = get_stdin "The above actions will be taken. Continue? (This cannot be undone) [No]: " | |
# The real deal | |
if "y yes".split.include? proceed.downcase | |
ok_failed system(rsync_command) | |
if CONFIG[:restart_apache] | |
restart_apache, ssh_port, ssh_host = CONFIG.values_at :restart_apache, :ssh_port, :ssh_host | |
puts | |
puts "## Restarting Apache server" | |
ok_failed system("ssh #{"-p "+ssh_port.to_s unless ssh_port == nil} #{ssh_host} '#{restart_apache}'") | |
end | |
else | |
puts "Deployment cancelled by user." | |
end | |
end | |
namespace :remote do | |
desc "Connect to the remote console" | |
task :console do | |
puts "## Initializing remote console" | |
puts "----------\nCommand: #{ssh_command}\n----------" | |
system(ssh_command) | |
end | |
desc "Show differences between local and remote files" | |
task :diff do | |
document_root, site_dir = CONFIG.values_at :document_root, :site_dir | |
# Get the local path | |
local_path = ENV['path'] ? ENV['path'] : site_dir | |
if File.exists?(local_path) | |
local_path = File.expand_path(local_path) | |
local_path = local_path + '/' if File.directory?(local_path) | |
end | |
# Build the remote path | |
remote_path = "#{document_root}/#{local_path.sub(File.expand_path(site_dir), '')}".gsub(/\/+/, '/') | |
# Files get compared straight-up | |
if File.file?(local_path) | |
system(%Q:bash -c 'diff -Naur#{'w' unless ENV['ignorewhitespace'].nil?} "#{local_path}" <(#{ssh_command "cat #{remote_path}"})':) | |
# Directories process each file | |
else | |
changes = `#{rsync_command '--dry-run'}` | |
num_changes = changes.lines.count | |
proceed = get_stdin "#{changes.lines.count} file(s) will be compared. Continue? [No]: " if num_changes > 10 | |
if proceed == nil or "y yes".split.include? proceed.downcase | |
changes.each_line do |line| | |
action, file = line.chomp.split(' ', 2) | |
system %Q:bash -c 'diff -Naur#{'w' unless ENV['ignorewhitespace'].nil?} "#{local_path + file}" <(#{ssh_command "cat #{remote_path + file}"})': | |
end | |
end | |
end | |
end | |
end | |
## -- Utility functions -- ## | |
def ssh_command(command=nil) | |
ssh_port, ssh_host = CONFIG.values_at :ssh_port, :ssh_host | |
"ssh #{"-p "+ssh_port.to_s unless ssh_port == nil} #{ssh_host} #{%Q'"#{command}"' unless command == nil}" | |
end | |
def rsync_command(options=nil) | |
document_root, rsync_delete, site_dir, ssh_port, ssh_host = | |
CONFIG.values_at :document_root, :rsync_delete, :site_dir, :ssh_port, :ssh_host | |
# Get the local path | |
local_path = ENV['path'] ? ENV['path'] : site_dir | |
if File.exists?(local_path) | |
local_path = File.expand_path(local_path) | |
local_path = local_path + '/' if File.directory?(local_path) | |
end | |
# Build the remote path | |
remote_path = "#{document_root}/#{local_path.sub(File.expand_path(site_dir), '')}".gsub(/\/+/, '/') | |
# Exclude file | |
exclude = "" | |
if File.exists?('./deploy-exclude') | |
exclude="--exclude-from '#{File.expand_path('./deploy-exclude')}'" | |
end | |
# Build rsync options | |
rsync_options = | |
"--archive --no-group --no-owner --no-perms --no-times --update " + | |
"--human-readable --compress --checksum " + | |
"--itemize-changes #{exclude} " + | |
"#{"--rsh='ssh -p #{ssh_port}' " unless ssh_port == nil}" + | |
"#{"--delete " unless rsync_delete == false}" + | |
"#{options} #{ENV['options']} " + | |
"#{local_path} #{ssh_host}:#{remote_path}" | |
return "rsync #{rsync_options}" | |
end | |
def ok_failed(condition) | |
if (condition) | |
puts "OK" | |
else | |
puts "FAILED" | |
end | |
end | |
def get_stdin(message) | |
print message | |
STDIN.gets.chomp | |
end | |
def ask(message, valid_options) | |
if valid_options | |
answer = get_stdin("#{message} #{valid_options.to_s.gsub(/"/, '').gsub(/, /,'/')} ") while !valid_options.include?(answer) | |
else | |
answer = get_stdin(message) | |
end | |
answer | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment