handy 0.0.15 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +18 -0
- data/Gemfile +6 -0
- data/LICENSE +4 -2
- data/README.md +10 -24
- data/Rakefile +2 -34
- data/handy.gemspec +20 -0
- data/lib/handy/config_loader.rb +25 -0
- data/lib/handy/delete_heroku_apps.rb +29 -0
- data/lib/handy/delete_merged_branches.rb +20 -0
- data/lib/handy/engine.rb +17 -0
- data/lib/handy/heroku_helpers.rb +63 -0
- data/lib/handy/trailing_whitespaces.rb +40 -0
- data/lib/handy/version.rb +1 -1
- data/lib/handy.rb +4 -9
- metadata +67 -88
- data/lib/handy/backup.rb +0 -19
- data/lib/handy/capistrano/delayed_job.rb +0 -24
- data/lib/handy/capistrano/remote_tasks.rb +0 -37
- data/lib/handy/capistrano/restart.rb +0 -21
- data/lib/handy/capistrano/restore_local.rb +0 -17
- data/lib/handy/capistrano/user_confirmation.rb +0 -22
- data/lib/handy/db2db.rb +0 -18
- data/lib/handy/dump2s3.rb +0 -88
- data/lib/handy/railtie.rb +0 -10
- data/lib/handy/restore.rb +0 -18
- data/lib/handy/tasks.rb +0 -119
- data/lib/handy/util.rb +0 -43
- data/test/helper.rb +0 -10
- data/test/test_handy.rb +0 -7
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
Copyright (c)
|
1
|
+
Copyright (c) 2012 Neeraj Singh
|
2
|
+
|
3
|
+
MIT License
|
2
4
|
|
3
5
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
6
|
a copy of this software and associated documentation files (the
|
@@ -17,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
19
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
20
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
21
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,33 +1,19 @@
|
|
1
|
-
#
|
1
|
+
# Handy
|
2
2
|
|
3
|
-
|
4
|
-
Creates a dump of data and structure which can been safely backed up.
|
5
|
-
file is backuped at <tt>tmp</tt> directory like this <tt>tmp/2011-02-10-22-05-40.sql.gz</tt>
|
3
|
+
Collection of handy tools collected over a period of time.
|
6
4
|
|
7
|
-
##
|
8
|
-
restores the data and structure from file
|
5
|
+
## Installation
|
9
6
|
|
10
|
-
|
11
|
-
Restores the data from production database to staging database. More options can be specified.
|
7
|
+
gem 'handy'
|
12
8
|
|
13
|
-
|
14
|
-
Creates a backup and then stores that backup on s3.
|
9
|
+
And then execute:
|
15
10
|
|
16
|
-
|
11
|
+
$ rake -T handy
|
17
12
|
|
13
|
+
## Settings
|
18
14
|
|
19
|
-
|
20
|
-
|
15
|
+
Besides having some useful rake tasks it also sets up a constant called
|
16
|
+
`Settings`. It reads the `application.yml` file and populates
|
17
|
+
`Settings`.
|
21
18
|
|
22
19
|
|
23
|
-
##rake handy:db:dump2s3:restore file=xxxx.sql.gz##
|
24
|
-
Restores the database with the data from s3.
|
25
|
-
|
26
|
-
|
27
|
-
##rake handy:web:ping site=www.eventsinindia.com##
|
28
|
-
Pings a site.
|
29
|
-
|
30
|
-
##For capistrano goodies look for files under directory capistrano##
|
31
|
-
|
32
|
-
|
33
|
-
Copyright (c) 2010 Neeraj Singh. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,34 +1,2 @@
|
|
1
|
-
|
2
|
-
require
|
3
|
-
|
4
|
-
desc 'Default: run unit tests.'
|
5
|
-
task :default => :test
|
6
|
-
|
7
|
-
begin
|
8
|
-
require 'jeweler'
|
9
|
-
require './lib/handy/version'
|
10
|
-
Jeweler::Tasks.new do |gem|
|
11
|
-
gem.name = "handy"
|
12
|
-
gem.version = Handy::VERSION
|
13
|
-
gem.summary = %Q{handy tools}
|
14
|
-
gem.description = %Q{handy tools that gets job done}
|
15
|
-
gem.email = "neerajdotname@gmail.com"
|
16
|
-
gem.homepage = "http://github.com/neerajdotname/handy"
|
17
|
-
gem.authors = ["Neeraj Singh"]
|
18
|
-
gem.files = FileList["[A-Z]*", "{lib,test}/**/*", 'init.rb']
|
19
|
-
|
20
|
-
gem.add_dependency('aws', '>= 2.3.21')
|
21
|
-
gem.add_dependency('capistrano', '>= 2.5.19')
|
22
|
-
end
|
23
|
-
Jeweler::GemcutterTasks.new
|
24
|
-
rescue LoadError
|
25
|
-
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
desc 'Test handy gem.'
|
30
|
-
Rake::TestTask.new(:test) do |t|
|
31
|
-
t.libs << 'lib' << 'test'
|
32
|
-
t.pattern = 'test/**/*_test.rb'
|
33
|
-
t.verbose = true
|
34
|
-
end
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
data/handy.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/handy/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Neeraj Singh"]
|
6
|
+
gem.email = ["neerajdotname@gmail.com"]
|
7
|
+
gem.description = %q{handy tool}
|
8
|
+
gem.summary = %q{Collection of handy tools}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "handy"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Handy::VERSION
|
17
|
+
|
18
|
+
gem.add_runtime_dependency 'hashr'
|
19
|
+
gem.add_runtime_dependency 'heroku'
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "hashr"
|
2
|
+
|
3
|
+
module Handy
|
4
|
+
class ConfigLoader
|
5
|
+
|
6
|
+
attr_reader :filename
|
7
|
+
|
8
|
+
def initialize(filename)
|
9
|
+
@filename = filename
|
10
|
+
end
|
11
|
+
|
12
|
+
def load(key = Rails.env)
|
13
|
+
file = Rails.root.join('config', filename)
|
14
|
+
return unless File.exist?(file)
|
15
|
+
|
16
|
+
hash = YAML.load(ERB.new(File.read(file)).result)
|
17
|
+
|
18
|
+
common_hash = hash['common'] || {}
|
19
|
+
env_hash = hash[key.to_s] || {}
|
20
|
+
|
21
|
+
final_hash = common_hash.deep_merge(env_hash)
|
22
|
+
::Hashr.new(final_hash)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
namespace :handy do
|
2
|
+
|
3
|
+
namespace :heroku do
|
4
|
+
|
5
|
+
def ask(message)
|
6
|
+
print message
|
7
|
+
%w(y yes).include? STDIN.gets.chomp.downcase
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Delete herokou apps."
|
11
|
+
task :delete_apps do
|
12
|
+
output = `heroku apps`
|
13
|
+
output.split(/\r?\n/).each do |record|
|
14
|
+
parts = record.split(' ')
|
15
|
+
puts parts.join('/')
|
16
|
+
name = parts.first
|
17
|
+
cmd = "heroku apps:destroy --app #{name} --confirm #{name}"
|
18
|
+
puts cmd
|
19
|
+
if ask('This command is destructive, proceed? (yes, no): ')
|
20
|
+
puts 'executing'
|
21
|
+
system cmd
|
22
|
+
end
|
23
|
+
puts ''
|
24
|
+
puts ''
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
namespace :handy do
|
2
|
+
|
3
|
+
namespace :git do
|
4
|
+
|
5
|
+
def ask(message)
|
6
|
+
print message
|
7
|
+
STDIN.gets.chomp.downcase == 'yes'
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Delete merged branches."
|
11
|
+
task :delete_merged_branches do
|
12
|
+
puts 'Removing all REMOTE merged branches from repository'
|
13
|
+
if ask('This command is destructive, proceed? (yes, no): ')
|
14
|
+
sh "git branch -r --merged master | sed 's/ *origin\\///' | grep -v 'master$' | grep -v 'production$' | grep -v 'staging$' | xargs -I% git push origin :%"
|
15
|
+
sh "git remote prune origin"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/lib/handy/engine.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Handy
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
|
4
|
+
initializer :load_application_yml, before: :load_environment_config do
|
5
|
+
::Settings = ConfigLoader.new('settings.yml').load
|
6
|
+
end
|
7
|
+
|
8
|
+
rake_tasks do
|
9
|
+
load 'handy/trailing_whitespaces.rb'
|
10
|
+
load 'handy/delete_merged_branches.rb'
|
11
|
+
load 'handy/heroku_helpers.rb'
|
12
|
+
load 'handy/delete_heroku_apps.rb'
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
def execute(cmd)
|
2
|
+
puts cmd
|
3
|
+
system cmd
|
4
|
+
end
|
5
|
+
|
6
|
+
namespace :handy do
|
7
|
+
|
8
|
+
namespace :heroku do
|
9
|
+
desc "Copy production data to development"
|
10
|
+
task :prod2development, :app do |t, args|
|
11
|
+
export2local "#{heroku_app_name(t, args)}-production"
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Copy staging data to development"
|
15
|
+
task :staging2development, :app do |t, args|
|
16
|
+
export2local "#{heroku_app_name(t, args)}-staging"
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Copy production data to staging"
|
20
|
+
task :prod2staging, :app do |t, args|
|
21
|
+
heroku_app_name = heroku_app_name(t, args)
|
22
|
+
src_app_name = "#{heroku_app_name}-production"
|
23
|
+
dst_app_name = "#{heroku_app_name}-staging"
|
24
|
+
|
25
|
+
get_src_db_url_cmd = "`heroku pgbackups:url --app #{src_app_name}`"
|
26
|
+
execute "heroku pgbackups:restore DATABASE #{get_src_db_url_cmd} --app #{dst_app_name} --confirm #{dst_app_name}"
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def export2local(app_name)
|
31
|
+
execute "heroku pgbackups:capture --expire --app #{app_name}"
|
32
|
+
execute "curl -o latest.dump `heroku pgbackups:url --app #{app_name}`"
|
33
|
+
execute restore_command + "; rm latest.dump"
|
34
|
+
end
|
35
|
+
|
36
|
+
def heroku_app_name t, args
|
37
|
+
args[:app] || ENV['APP_NAME'] || Rails.root.basename || abort(<<ERROR_MSG)
|
38
|
+
Error: heroku app name is missing. This rake task should be invoked like this:
|
39
|
+
|
40
|
+
rake #{t.name}['tweli'].
|
41
|
+
ERROR_MSG
|
42
|
+
end
|
43
|
+
|
44
|
+
def local_database
|
45
|
+
database_config && database_config[:database] ||
|
46
|
+
abort('Error: Please check your database.yml since no database was found.')
|
47
|
+
end
|
48
|
+
|
49
|
+
def database_config
|
50
|
+
@database_config ||= Handy::ConfigLoader.new('database.yml').load
|
51
|
+
end
|
52
|
+
|
53
|
+
def restore_command
|
54
|
+
result = "pg_restore --verbose --clean --no-acl --no-owner"
|
55
|
+
result += " -h#{database_config[:host]}" if database_config[:host].present?
|
56
|
+
result += " -U#{database_config[:username]}" if database_config[:username].present?
|
57
|
+
result = "PGPASSWORD=#{database_config[:password]} #{result}" if database_config[:password].present?
|
58
|
+
|
59
|
+
result + " -d #{local_database} latest.dump"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
namespace :handy do
|
2
|
+
|
3
|
+
# copied from https://gist.github.com/2922427
|
4
|
+
namespace :source do
|
5
|
+
def find_and_replace_in_source_files(find, replace)
|
6
|
+
puts "Search and replace #{find.inspect} => #{replace.inspect}"
|
7
|
+
|
8
|
+
files = %w[ .autotest .rspec .rvmrc Gemfile Procfile config.ru ].select{|f| File.exist?(f) }
|
9
|
+
directories = %w[app config lib public script spec test] # exclude bin, db, doc, log, and tmp
|
10
|
+
directories.each do |d|
|
11
|
+
files += Dir[File.join(d, "**/*.{rb,rake,haml,erb,builder,js,coffee,css,scss}")]
|
12
|
+
end
|
13
|
+
|
14
|
+
files.each do |file_name|
|
15
|
+
text = File.open(file_name, 'r'){ |file| file.read }
|
16
|
+
if text.gsub!(find, replace)
|
17
|
+
puts "rewriting #{file_name}..."
|
18
|
+
File.open(file_name, 'w'){|file| file.write(text)}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Replace all tabs in source code files with two spaces"
|
24
|
+
task :detab do
|
25
|
+
find_and_replace_in_source_files("\t", " ")
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Remove trailing whitespace at the ends of lines"
|
29
|
+
task :detrail do
|
30
|
+
find_and_replace_in_source_files(/ +$/, '')
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Replace all instances of {pattern} with {result}"
|
34
|
+
task :gsub, :pattern, :result do |t, args|
|
35
|
+
find_and_replace_in_source_files(Regexp.new(args[:pattern] || ENV['PATTERN']), args[:result] || ENV['RESULT'])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
data/lib/handy/version.rb
CHANGED
data/lib/handy.rb
CHANGED
@@ -1,11 +1,6 @@
|
|
1
|
-
require
|
1
|
+
require "handy/version"
|
2
|
+
require "handy/engine"
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
require 'handy/restore'
|
6
|
-
require 'handy/db2db'
|
7
|
-
require 'handy/dump2s3'
|
8
|
-
|
9
|
-
if defined? Rails
|
10
|
-
require 'handy/railtie'
|
4
|
+
module Handy
|
5
|
+
autoload :ConfigLoader, 'handy/config_loader'
|
11
6
|
end
|
metadata
CHANGED
@@ -1,118 +1,97 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: handy
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 15
|
10
|
-
version: 0.0.15
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.17
|
5
|
+
prerelease:
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Neeraj Singh
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
name: aws
|
23
|
-
prerelease: false
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
12
|
+
date: 2013-05-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: hashr
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
25
17
|
none: false
|
26
|
-
requirements:
|
27
|
-
- -
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 2
|
32
|
-
- 3
|
33
|
-
- 21
|
34
|
-
version: 2.3.21
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
35
22
|
type: :runtime
|
36
|
-
version_requirements: *id001
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
name: capistrano
|
39
23
|
prerelease: false
|
40
|
-
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
25
|
none: false
|
42
|
-
requirements:
|
43
|
-
- -
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: heroku
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
51
38
|
type: :runtime
|
52
|
-
|
53
|
-
|
54
|
-
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description: handy tool
|
47
|
+
email:
|
48
|
+
- neerajdotname@gmail.com
|
55
49
|
executables: []
|
56
|
-
|
57
50
|
extensions: []
|
58
|
-
|
59
|
-
|
60
|
-
-
|
61
|
-
-
|
62
|
-
files:
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gitignore
|
54
|
+
- Gemfile
|
63
55
|
- LICENSE
|
64
56
|
- README.md
|
65
57
|
- Rakefile
|
58
|
+
- handy.gemspec
|
66
59
|
- lib/handy.rb
|
67
|
-
- lib/handy/
|
68
|
-
- lib/handy/
|
69
|
-
- lib/handy/
|
70
|
-
- lib/handy/
|
71
|
-
- lib/handy/
|
72
|
-
- lib/handy/
|
73
|
-
- lib/handy/db2db.rb
|
74
|
-
- lib/handy/dump2s3.rb
|
75
|
-
- lib/handy/railtie.rb
|
76
|
-
- lib/handy/restore.rb
|
77
|
-
- lib/handy/tasks.rb
|
78
|
-
- lib/handy/util.rb
|
60
|
+
- lib/handy/config_loader.rb
|
61
|
+
- lib/handy/delete_heroku_apps.rb
|
62
|
+
- lib/handy/delete_merged_branches.rb
|
63
|
+
- lib/handy/engine.rb
|
64
|
+
- lib/handy/heroku_helpers.rb
|
65
|
+
- lib/handy/trailing_whitespaces.rb
|
79
66
|
- lib/handy/version.rb
|
80
|
-
|
81
|
-
- test/test_handy.rb
|
82
|
-
has_rdoc: true
|
83
|
-
homepage: http://github.com/neerajdotname/handy
|
67
|
+
homepage: ''
|
84
68
|
licenses: []
|
85
|
-
|
86
69
|
post_install_message:
|
87
70
|
rdoc_options: []
|
88
|
-
|
89
|
-
require_paths:
|
71
|
+
require_paths:
|
90
72
|
- lib
|
91
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
74
|
none: false
|
93
|
-
requirements:
|
94
|
-
- -
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
|
97
|
-
segments:
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
segments:
|
98
80
|
- 0
|
99
|
-
|
100
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
hash: 157870693463647709
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
83
|
none: false
|
102
|
-
requirements:
|
103
|
-
- -
|
104
|
-
- !ruby/object:Gem::Version
|
105
|
-
|
106
|
-
segments:
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
segments:
|
107
89
|
- 0
|
108
|
-
|
90
|
+
hash: 157870693463647709
|
109
91
|
requirements: []
|
110
|
-
|
111
92
|
rubyforge_project:
|
112
|
-
rubygems_version: 1.
|
93
|
+
rubygems_version: 1.8.23
|
113
94
|
signing_key:
|
114
95
|
specification_version: 3
|
115
|
-
summary: handy tools
|
116
|
-
test_files:
|
117
|
-
- test/helper.rb
|
118
|
-
- test/test_handy.rb
|
96
|
+
summary: Collection of handy tools
|
97
|
+
test_files: []
|
data/lib/handy/backup.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module Handy
|
2
|
-
|
3
|
-
class Backup
|
4
|
-
def self.run(env, file, backup_file)
|
5
|
-
util = Util.retrieve_db_info(env)
|
6
|
-
cmd = util.mysqldump_command
|
7
|
-
cmd << " --opt --skip-add-locks #{util.database} >> #{file}"
|
8
|
-
Util.execute_cmd(cmd)
|
9
|
-
|
10
|
-
#-c --stdout write on standard output, keep original files unchanged
|
11
|
-
#-q quite
|
12
|
-
#-9 best compression
|
13
|
-
Util.execute_cmd "gzip -q9 #{file}"
|
14
|
-
Util.execute_cmd "mv #{file}.gz #{backup_file}"
|
15
|
-
Util.pretty_msg "Backup done at #{File.expand_path(backup_file)}"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
-
|
3
|
-
namespace :delayed_job do
|
4
|
-
desc "Start delayed_job process"
|
5
|
-
task :start, :roles => :app do
|
6
|
-
run "cd #{current_path}; RAILS_ENV=#{stage} script/delayed_job start"
|
7
|
-
end
|
8
|
-
|
9
|
-
desc "Stop delayed_job process"
|
10
|
-
task :stop, :roles => :app do
|
11
|
-
run "cd #{current_path}; RAILS_ENV=#{stage} script/delayed_job stop"
|
12
|
-
end
|
13
|
-
|
14
|
-
desc "Restart delayed_job process"
|
15
|
-
task :restart, :roles => :app do
|
16
|
-
run "cd #{current_path}; RAILS_ENV=#{stage} script/delayed_job restart"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
after "deploy:start", "delayed_job:start"
|
21
|
-
after "deploy:stop", "delayed_job:stop"
|
22
|
-
after "deploy:restart", "delayed_job:restart"
|
23
|
-
|
24
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
-
|
3
|
-
# Usage:
|
4
|
-
#
|
5
|
-
# cap production remote 'tail -f log/production.log'
|
6
|
-
# cap production rake 'db:prod2staging'
|
7
|
-
|
8
|
-
set :sudo_call, ''
|
9
|
-
|
10
|
-
desc 'makes remote/rake calls to be executed with sudo'
|
11
|
-
task :use_sudo do
|
12
|
-
set :sudo_call, 'sudo'
|
13
|
-
end
|
14
|
-
|
15
|
-
desc 'run rake task'
|
16
|
-
task :rake do
|
17
|
-
ARGV.values_at(Range.new(ARGV.index('rake')+1,-1)).each do |task|
|
18
|
-
run "cd #{current_path}; #{sudo_call} RAILS_ENV=#{stage} rake #{task}"
|
19
|
-
end
|
20
|
-
exit(0)
|
21
|
-
end
|
22
|
-
|
23
|
-
desc 'run remote command'
|
24
|
-
task :remote do
|
25
|
-
command=ARGV.values_at(Range.new(ARGV.index('remote')+1, -1))
|
26
|
-
run "cd #{current_path}; #{sudo_call} RAILS_ENV=#{stage} #{command*' '}"
|
27
|
-
exit(0)
|
28
|
-
end
|
29
|
-
|
30
|
-
desc 'run specified rails code on server'
|
31
|
-
task :runner do
|
32
|
-
command=ARGV.values_at(Range.new(ARGV.index('runner')+1, -1))
|
33
|
-
run "cd #{current_path}; RAILS_ENV=#{stage} rails runner '#{command*' '}'"
|
34
|
-
exit(0)
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
-
|
3
|
-
# source: http://tomcopeland.blogs.com/juniordeveloper/2008/05/mod_rails-and-c.html
|
4
|
-
namespace :deploy do
|
5
|
-
desc "Restarting mod_rails with restart.txt"
|
6
|
-
task :restart, :roles => :app, :except => { :no_release => true } do
|
7
|
-
run "touch #{current_path}/tmp/restart.txt"
|
8
|
-
end
|
9
|
-
|
10
|
-
[:start, :stop].each do |t|
|
11
|
-
desc "#{t} task is a no-op with mod_rails"
|
12
|
-
task t, :roles => :app do ; end
|
13
|
-
end
|
14
|
-
|
15
|
-
desc "invoke the db migration"
|
16
|
-
task:migrate, :roles => :app do
|
17
|
-
send(run_method, "cd #{current_path} && rake db:migrate RAILS_ENV=#{stage} ")
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
-
|
3
|
-
# Usage:
|
4
|
-
#
|
5
|
-
# Following capistrano task will restore your local database with database from remote database
|
6
|
-
# cap production db:restore_local
|
7
|
-
namespace :db do
|
8
|
-
desc 'restore local file with data from remote machine'
|
9
|
-
task :restore_local do
|
10
|
-
timestamp = Time.now.strftime("%Y-%m-%d-%H-%M-%S")
|
11
|
-
send(run_method, "cd #{current_path} && rake handy:db:backup timestamp=#{timestamp} RAILS_ENV=#{stage} ")
|
12
|
-
get "#{deploy_to}/current/tmp/#{timestamp}.sql.gz","tmp/#{timestamp}.sql.gz"
|
13
|
-
system("rake handy:db:restore file='#{timestamp}.sql.gz'")
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
-
|
3
|
-
before "deploy:update_code", "user_confirmation_for_production_deployment"
|
4
|
-
task :user_confirmation_for_production_deployment, roles => :app do
|
5
|
-
if "#{stage}" == 'production'
|
6
|
-
message = %Q{
|
7
|
-
****************************************************************************************************************
|
8
|
-
* You are pushing to production.
|
9
|
-
*
|
10
|
-
* production is deployed from production branch. So make sure that you merged your changes to production branch.
|
11
|
-
*
|
12
|
-
* You have pushed your changes to github. Right.
|
13
|
-
*
|
14
|
-
* continue(y/n)
|
15
|
-
****************************************************************************************************************
|
16
|
-
}
|
17
|
-
answer = Capistrano::CLI.ui.ask(message)
|
18
|
-
abort "deployment to production was stopped" unless answer == 'y'
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
data/lib/handy/db2db.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
module Handy
|
2
|
-
class Db2db
|
3
|
-
def self.run(from_env, to_env, file)
|
4
|
-
from_params = "-Q --add-drop-table -O add-locks=FALSE -O lock-tables=FALSE"
|
5
|
-
from_util = Util.retrieve_db_info(from_env)
|
6
|
-
cmd = from_util.mysqldump_command
|
7
|
-
cmd << " #{from_params} #{from_util.database} > #{file} "
|
8
|
-
Util.execute_cmd(cmd)
|
9
|
-
|
10
|
-
to_util = Util.retrieve_db_info(to_env)
|
11
|
-
cmd = to_util.mysql_command
|
12
|
-
cmd << " < #{file}"
|
13
|
-
Util.execute_cmd(cmd)
|
14
|
-
|
15
|
-
Util.pretty_msg "#{to_env} database has been restored with #{from_env} database"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
data/lib/handy/dump2s3.rb
DELETED
@@ -1,88 +0,0 @@
|
|
1
|
-
module Handy
|
2
|
-
class S3
|
3
|
-
|
4
|
-
attr_accessor :bucket_name, :access_key_id, :secret_access_key, :bucket_instance
|
5
|
-
|
6
|
-
# This module relies on following things to be present:
|
7
|
-
#
|
8
|
-
# AppConfig.s3_bucket_name
|
9
|
-
# AppConfig.s3_access_key_id
|
10
|
-
# AppConfig.s3_secret_access_key
|
11
|
-
#
|
12
|
-
def initialize(env)
|
13
|
-
@bucket_name = AppConfig.s3_bucket_name
|
14
|
-
@access_key_id = AppConfig.s3_access_key_id
|
15
|
-
@secret_access_key = AppConfig.s3_secret_access_key
|
16
|
-
@s3_instance = Aws::S3.new(access_key_id, secret_access_key)
|
17
|
-
|
18
|
-
if @bucket_name.nil? || @access_key_id.nil? || @secret_access_key.nil?
|
19
|
-
raise "looks like aws/s3 credentials are not set properly"
|
20
|
-
end
|
21
|
-
|
22
|
-
@bucket_instance = Aws::S3::Bucket.create(@s3_instance, bucket_name)
|
23
|
-
begin
|
24
|
-
@bucket_instance.keys
|
25
|
-
rescue
|
26
|
-
@bucket_instance = Aws::S3::Bucket.create(@s3_instance, bucket_name, true)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def store(file_name, file_data)
|
31
|
-
@bucket_instance.put(file_name, file_data)
|
32
|
-
end
|
33
|
-
|
34
|
-
def fetch(file_name)
|
35
|
-
connected
|
36
|
-
AWS::S3::S3Object.find(file_name, bucket)
|
37
|
-
|
38
|
-
file = Tempfile.new("dump")
|
39
|
-
open(file.path, 'w') do |f|
|
40
|
-
AWS::S3::S3Object.stream(file_name, bucket) do |chunk|
|
41
|
-
f.write chunk
|
42
|
-
end
|
43
|
-
end
|
44
|
-
file
|
45
|
-
end
|
46
|
-
|
47
|
-
|
48
|
-
def delete(file_name)
|
49
|
-
if object = AWS::S3::S3Object.find(file_name, bucket)
|
50
|
-
object.delete
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
|
59
|
-
module Handy
|
60
|
-
class Dump2s3
|
61
|
-
|
62
|
-
def self.run(env, file_name)
|
63
|
-
s3 = Handy::S3.new(Rails.env)
|
64
|
-
s3.store(file_name, open(Rails.root.join('tmp', file_name)))
|
65
|
-
Handy::Util.pretty_msg("#{file_name} has been backedup at s3.")
|
66
|
-
end
|
67
|
-
|
68
|
-
def self.list(env)
|
69
|
-
s3 = Handy::S3.new(Rails.env)
|
70
|
-
Handy::Util.pretty_msg("List of files on s3 for bucket #{s3.bucket_name}")
|
71
|
-
s3.bucket_instance.keys.each {|e| puts e}
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.restore(env, file_name)
|
75
|
-
s3 = Handy::S3.new(Rails.env)
|
76
|
-
keyinfo = s3.bucket_instance.key(file_name)
|
77
|
-
raise "no file named #{file_name} was found on s3. Please check the file list on s3" if keyinfo.blank?
|
78
|
-
data = s3.bucket_instance.get(file_name)
|
79
|
-
storage_dir = Rails.root.join('tmp', file_name)
|
80
|
-
open(storage_dir, 'w') do |f|
|
81
|
-
f.write data
|
82
|
-
end
|
83
|
-
Handy::Util.pretty_msg("file #{file_name} has been downloaded to #{storage_dir.expand_path}")
|
84
|
-
end
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
end
|
data/lib/handy/railtie.rb
DELETED
data/lib/handy/restore.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
module Handy
|
2
|
-
class Restore
|
3
|
-
def self.run(file, env)
|
4
|
-
util = Util.retrieve_db_info(env)
|
5
|
-
|
6
|
-
if file =~ /\.gz/
|
7
|
-
puts "decompressing backup"
|
8
|
-
result = system("gzip -d #{file}" )
|
9
|
-
raise("backup decompression failed. msg: #{$?}" ) unless result
|
10
|
-
end
|
11
|
-
|
12
|
-
cmd = "#{util.mysql_command} < #{file.gsub('.gz','')}"
|
13
|
-
|
14
|
-
Util.execute_cmd(cmd)
|
15
|
-
Util.pretty_msg "database has been restored"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
data/lib/handy/tasks.rb
DELETED
@@ -1,119 +0,0 @@
|
|
1
|
-
namespace :handy do
|
2
|
-
namespace :web do
|
3
|
-
desc "Ping a site"
|
4
|
-
task :ping => :environment do
|
5
|
-
begin
|
6
|
-
puts "Usage: rake handy:web:ping site=www.xxx.com"
|
7
|
-
site = ENV['site']
|
8
|
-
cmd = "curl http://#{site}> /dev/null 2>&1 &"
|
9
|
-
system(cmd)
|
10
|
-
rescue => e
|
11
|
-
HoptoadNotifier.notify(e, :parameters => {:site => site})
|
12
|
-
puts e.message.inspect + e.backtrace.join('\n')
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
namespace :db do
|
18
|
-
|
19
|
-
desc "Load schema and data from a local sql file."
|
20
|
-
task :restore => :environment do
|
21
|
-
begin
|
22
|
-
puts "Usage: rake handy:db:restore file=xxxxxxxxx.sql[.gz]"
|
23
|
-
file_name = ENV['file']
|
24
|
-
raise "file was not supplied. Check Usage." unless file_name
|
25
|
-
file = File.join(Rails.root, 'tmp', file_name)
|
26
|
-
raise "file was not found" unless File.exists?(file)
|
27
|
-
Rake::Task["db:drop"].invoke
|
28
|
-
Rake::Task["db:create"].invoke
|
29
|
-
|
30
|
-
Handy::Restore.run(file, Rails.env)
|
31
|
-
rescue => e
|
32
|
-
HoptoadNotifier.notify(e, :parameters => {:file => file})
|
33
|
-
puts e.message.inspect + e.backtrace.join('\r\n')
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
desc <<-DESC
|
38
|
-
This task backups the database to a file. It will keep a maximum of 10 backed up copies.
|
39
|
-
The files are backed up at shared directory on remote server.
|
40
|
-
This task should be executed before any deploy to production.
|
41
|
-
Files are backed at Rails.root/../../shared/db_backups on the remote server
|
42
|
-
DESC
|
43
|
-
task :backup => [:environment] do
|
44
|
-
begin
|
45
|
-
timestamp = ENV['timestamp'] || Time.zone.now.strftime("%Y-%m-%d-%H-%M-%S")
|
46
|
-
file = "#{timestamp}.sql"
|
47
|
-
backup_dir = File.join (Rails.root, 'tmp')
|
48
|
-
FileUtils.mkdir_p(backup_dir) unless File.exists?(backup_dir) && File.directory?(backup_dir)
|
49
|
-
backup_file = File.join(backup_dir, "#{file}.gz")
|
50
|
-
|
51
|
-
Handy::Backup.run(Rails.env, file, backup_file)
|
52
|
-
rescue => e
|
53
|
-
HoptoadNotifier.notify(e, :parameters => {:file => file})
|
54
|
-
puts e.message.inspect + e.backtrace.join('\n')
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
|
59
|
-
desc "Copy production database to staging database. Or copy data from any database to any other datbase."
|
60
|
-
task :db2db => :environment do
|
61
|
-
begin
|
62
|
-
puts "Usage: handy:db:db2db from_env=production to_env=staging"
|
63
|
-
from_env = ENV['from_env'] || 'production'
|
64
|
-
to_env = ENV['to_env'] || 'staging'
|
65
|
-
file = "#{Rails.root}/tmp/#{from_env}.data"
|
66
|
-
|
67
|
-
Handy::Db2db.run(from_env, to_env, file)
|
68
|
-
rescue => e
|
69
|
-
HoptoadNotifier.notify(e, :parameters => {:from_env => from_env, :to_env => to_env })
|
70
|
-
puts e.message.inspect + e.backtrace.join('\n')
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
desc "Copy database dump to s3"
|
75
|
-
task :dump2s3 => :environment do
|
76
|
-
begin
|
77
|
-
timestamp = Time.zone.now.strftime("%Y-%m-%d-%H-%M-%S")
|
78
|
-
file = "#{timestamp}.sql.gz"
|
79
|
-
ENV['file'] = file
|
80
|
-
Rake::Task["handy:db:backup"].invoke
|
81
|
-
|
82
|
-
Handy::Dump2s3.run(Rails.env, file)
|
83
|
-
rescue => e
|
84
|
-
HoptoadNotifier.notify(e, :parameters => {:file => file})
|
85
|
-
puts e.message.inspect + e.backtrace.join('\n')
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
namespace :dump2s3 do
|
90
|
-
|
91
|
-
desc "list all files stored at s3"
|
92
|
-
task :list => :environment do
|
93
|
-
begin
|
94
|
-
Handy::Dump2s3.list(Rails.env)
|
95
|
-
rescue => e
|
96
|
-
HoptoadNotifier.notify(e)
|
97
|
-
a = e.message.inspect
|
98
|
-
b = e.backtrace.join('\n')
|
99
|
-
puts a + b
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
desc "restore data from s3"
|
104
|
-
task :restore => :environment do
|
105
|
-
begin
|
106
|
-
file = ENV['file']
|
107
|
-
raise "No file was specified. Usage: rake handy:db:dump2s3:restore file=xxxx" if file.blank?
|
108
|
-
Handy::Dump2s3.restore(Rails.env, file)
|
109
|
-
Rake::Task["handy:db:restore"].invoke
|
110
|
-
rescue => e
|
111
|
-
HoptoadNotifier.notify(e, :parameters => {:file => file})
|
112
|
-
puts e.message.inspect + e.backtrace.join('\n')
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
end
|
117
|
-
|
118
|
-
end
|
119
|
-
end
|
data/lib/handy/util.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
module Handy
|
2
|
-
|
3
|
-
class Util
|
4
|
-
attr_accessor :username, :password, :database
|
5
|
-
def initialize(*args)
|
6
|
-
@username, @password, @database = *args
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.retrieve_db_info(env)
|
10
|
-
config = YAML.load_file(Rails.root.join('config', 'database.yml'))
|
11
|
-
self.new(config[env]['username'], config[env]['password'], config[env]['database'])
|
12
|
-
end
|
13
|
-
|
14
|
-
def mysql_command
|
15
|
-
a = ['mysql']
|
16
|
-
a << "-u #{username}"
|
17
|
-
a << "-p'#{password}'" unless password.blank?
|
18
|
-
a << database
|
19
|
-
a.join(' ')
|
20
|
-
end
|
21
|
-
|
22
|
-
def mysqldump_command
|
23
|
-
a = ['mysqldump']
|
24
|
-
a << "-u #{username}"
|
25
|
-
a << "-p'#{password}'" unless password.blank?
|
26
|
-
a.join(' ')
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.execute_cmd(cmd)
|
30
|
-
puts "executing: #{cmd}"
|
31
|
-
system cmd
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.pretty_msg(msg)
|
35
|
-
puts ''
|
36
|
-
puts '*'*100
|
37
|
-
puts ('*' << ' '*5 << msg)
|
38
|
-
puts '*'*100
|
39
|
-
puts ''
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
data/test/helper.rb
DELETED