Skip to content

Instantly share code, notes, and snippets.

@fstrube
Created June 5, 2012 14:17
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save fstrube/2875280 to your computer and use it in GitHub Desktop.
Save fstrube/2875280 to your computer and use it in GitHub Desktop.
Rake tasks for deploying a web app via rsync, and comparing local / remote file changes
## -- 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 "#{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 "#{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 == "no"}" +
"#{options} #{ENV['options']} " +
"#{local_path} #{ssh_host}:#{remote_path}"
return "rsync #{rsync_options}"
end
# Include all rake files in the tasks directory
Dir.glob('tasks/*.rake').each { |r| import r }
# Read configuration from tasks/config.yaml
require 'yaml'
CONFIG = YAML.load_file('tasks/config.yaml')[ENV['env'] || 'development']
# Default utility functions available in all tasks
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
@fstrube
Copy link
Author

fstrube commented Jun 5, 2012

Borrowed some from the Octopress.org Rakefile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment