rosie 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +26 -0
- data/LICENSE +20 -0
- data/README.md +58 -0
- data/lib/rosie/version.rb +3 -0
- data/lib/rosie.rb +41 -0
- data/lib/tasks/rosie.rake +102 -0
- data/rosie.gemspec +23 -0
- metadata +86 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*~
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm --create ruby-1.9.2-p0@rosie
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rosie (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.1.2)
|
10
|
+
rake (0.9.2)
|
11
|
+
rspec (2.6.0)
|
12
|
+
rspec-core (~> 2.6.0)
|
13
|
+
rspec-expectations (~> 2.6.0)
|
14
|
+
rspec-mocks (~> 2.6.0)
|
15
|
+
rspec-core (2.6.4)
|
16
|
+
rspec-expectations (2.6.0)
|
17
|
+
diff-lcs (~> 1.1.2)
|
18
|
+
rspec-mocks (2.6.0)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
rake (~> 0.9)
|
25
|
+
rosie!
|
26
|
+
rspec
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Rogers Yun Enterprises LLC (2RYE)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
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.
|
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# Rosie
|
2
|
+
|
3
|
+
## Intro
|
4
|
+
|
5
|
+
Backup and restore your MySQL db and dependent local assets (e.g. PaperClip uploads)
|
6
|
+
|
7
|
+
Named after Rosie, the maid from the Jetsons (http://en.wikipedia.org/wiki/Rosie_the_Robot_Maid#Rosie). The gem provides two rake tasks which will backup or restore a MySQL database along with any dependent file system assets (like uploaded files from PaperClip) into a single timestamped file.
|
8
|
+
|
9
|
+
## Requirements
|
10
|
+
|
11
|
+
* Rails3
|
12
|
+
* MySQL > 5 with commandline tools (mysql, mysqladmin, mysqldump)
|
13
|
+
* Unix(ish) system shell with tar
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add rosie to your Gemfile:
|
18
|
+
|
19
|
+
<pre>
|
20
|
+
gem 'rosie'
|
21
|
+
</pre>
|
22
|
+
|
23
|
+
Use bundler to install it:
|
24
|
+
|
25
|
+
<pre>
|
26
|
+
bundle install
|
27
|
+
</pre>
|
28
|
+
|
29
|
+
## Configuration
|
30
|
+
|
31
|
+
Configuration values can be set by placing a rosie.yml file in your config directory. Default keys and values are as follows:
|
32
|
+
|
33
|
+
<pre>
|
34
|
+
# sample rosie.yml
|
35
|
+
#
|
36
|
+
backup_dir:backups
|
37
|
+
assets_dir:public/system
|
38
|
+
mysql_bin_dir:
|
39
|
+
|
40
|
+
</pre>
|
41
|
+
|
42
|
+
* `backup_dir`: This should be specified relative to your Rails root. This setting would give you `#{Rails.root}/backups`.
|
43
|
+
* `assets_dir`: This should be specified relative to your Rails root. This directory is the one that is holding any system assets you'd like to have backed up along side the database dump.
|
44
|
+
* `mysql_bin_dir`: If mysql and mysqldump are not on the path of the user running this rake task, you may need to specify the directory where those commandline applications live. This should be an absolute path. By default, Rosie will try to find these in the user's PATH.
|
45
|
+
|
46
|
+
## Validation
|
47
|
+
|
48
|
+
Tested on OSX 10.6/Ubuntu 11
|
49
|
+
|
50
|
+
## Usage
|
51
|
+
|
52
|
+
## TODO
|
53
|
+
* add ability to backup remote databases (not on localhost)
|
54
|
+
* make Rails2.3.x compatible
|
55
|
+
* add alternate database support
|
56
|
+
|
57
|
+
## Credits
|
58
|
+
Developed by Jon Rogers and Jeremy Yun @ 2rye.com
|
data/lib/rosie.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
rootpath = File.join(File.dirname(__FILE__),'..')
|
2
|
+
require File.join(rootpath, 'lib/rosie/version')
|
3
|
+
|
4
|
+
Dir[File.join(rootpath, "lib/tasks/**/*.rake")].each { |ext| load ext } if defined?(Rake)
|
5
|
+
|
6
|
+
module Rosie
|
7
|
+
class Config
|
8
|
+
@@allowed_attributes = [:backup_dir, :assets_dir, :mysql_bin_dir, :config_file]
|
9
|
+
|
10
|
+
attr_accessor *@@allowed_attributes
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
_config = {"backup_dir"=>"backups", "assets_dir"=>"public/system", "mysql_bin_dir"=>nil}
|
14
|
+
self.config_file = File.join(Rails.root, 'config/rosie.yml')
|
15
|
+
if File.exists? self.config_file
|
16
|
+
_config.merge!(YAML.load(File.open(self.config_file)))
|
17
|
+
end
|
18
|
+
_config.keys.each do |attr|
|
19
|
+
self.send(attr+"=",_config[attr]) if @@allowed_attributes.include? attr.to_sym
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def backup_dir
|
24
|
+
File.join(Rails.root, @backup_dir)
|
25
|
+
end
|
26
|
+
|
27
|
+
def assets_dir
|
28
|
+
File.join(Rails.root, @assets_dir)
|
29
|
+
end
|
30
|
+
|
31
|
+
def mysql_cmd
|
32
|
+
mysql_bin_dir.present? ? File.join(mysql_bin_dir, 'mysql') : 'mysql'
|
33
|
+
end
|
34
|
+
|
35
|
+
def mysqldump_cmd
|
36
|
+
mysql_bin_dir.present? ? File.join(mysql_bin_dir, 'mysqldump') : 'mysqldump'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'find'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
rosie = nil
|
7
|
+
ts = nil
|
8
|
+
|
9
|
+
def get_db_config
|
10
|
+
alldbconf = YAML.load_file( File.join( [Rails.root, 'config','database.yml' ] ))
|
11
|
+
env = Rails.env
|
12
|
+
alldbconf[env]
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_db_cmdline_args
|
16
|
+
dbcnf = get_db_config
|
17
|
+
args = []
|
18
|
+
# NOTE: Assuming that database is running on localhost
|
19
|
+
# TODO - if you use other args like :socket, or ? they are ignored
|
20
|
+
# we could add host, port etc to make this more flexible
|
21
|
+
[['--user=','username'], ['--password=','password']].each do |entry|
|
22
|
+
if dbcnf[entry[1]].present?
|
23
|
+
args << "#{entry[0]}#{dbcnf[entry[1]]}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
args
|
27
|
+
end
|
28
|
+
|
29
|
+
namespace :rosie do
|
30
|
+
task :init do
|
31
|
+
rosie = Rosie::Config.new
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "show config"
|
35
|
+
task :dump_config => :init do
|
36
|
+
puts "Rosie Config: read from #{rosie.config_file}"
|
37
|
+
puts "mysql: #{rosie.mysql_cmd}"
|
38
|
+
puts "mysqldump: #{rosie.mysqldump_cmd}"
|
39
|
+
puts "backup dir: #{rosie.backup_dir}"
|
40
|
+
puts "assets dir: #{rosie.assets_dir}"
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "restore data from backup tarball"
|
44
|
+
task :restore => :init do
|
45
|
+
puts "Restoring data..."
|
46
|
+
tarball = ENV["datafile"]
|
47
|
+
if tarball.present?
|
48
|
+
tarball = File.absolute_path(tarball)
|
49
|
+
tmp = File.join(Dir.tmpdir, "rosie-restore")
|
50
|
+
FileUtils.remove_dir(tmp, true)
|
51
|
+
FileUtils.mkdir_p(tmp)
|
52
|
+
if !Dir.exists?(tmp)
|
53
|
+
msg = "Unable to create a temporary directory. Please check your file permissions.\nAttempted to create #{tmp}"
|
54
|
+
raise msg
|
55
|
+
end
|
56
|
+
files_before = Dir.entries(tmp)
|
57
|
+
sh "cd #{tmp} && tar -xzf #{tarball}"
|
58
|
+
ts = Dir.entries(tmp).reject{ |f| files_before.include? f }.first
|
59
|
+
unless ts.present?
|
60
|
+
puts "*** Something went wrong while trying to unpack the datafile."
|
61
|
+
exit 1
|
62
|
+
end
|
63
|
+
dbcnf = get_db_config
|
64
|
+
data_dir = File.join(tmp, ts)
|
65
|
+
image_tarball = File.join(data_dir, Dir.entries(data_dir).select{|f| f =~ /#{ts}.*\.tar/}.first)
|
66
|
+
sql_dump = File.join(data_dir, Dir.entries(data_dir).select{|f| f =~ /#{ts}.*\.sql/}.first)
|
67
|
+
args = get_db_cmdline_args
|
68
|
+
sh "tar -C #{rosie.assets_dir} -xf #{image_tarball} && #{rosie.mysql_cmd} #{args.join(' ')} #{dbcnf['database']} < #{sql_dump}"
|
69
|
+
|
70
|
+
else
|
71
|
+
puts "*** You must specify the datafile from which to restore"
|
72
|
+
puts "*** e.g. % datafile=/home/me/2011010101.tgz rake rosie:restore"
|
73
|
+
exit 1
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
desc "backup all data"
|
78
|
+
task :backup => ["rosie:backups:db", "rosie:backups:assets"] do
|
79
|
+
sh "cd #{rosie.backup_dir}/#{ts}/../ && tar -czvf #{ts}.tgz ./#{ts} && rm -rf #{ts}"
|
80
|
+
end
|
81
|
+
|
82
|
+
namespace :backups do
|
83
|
+
task :init => 'rosie:init' do
|
84
|
+
ts = Time.now.strftime('%Y%m%d%H%m%S')
|
85
|
+
end
|
86
|
+
|
87
|
+
task :db => :init do
|
88
|
+
dbcnf = get_db_config
|
89
|
+
db_file = "#{dbcnf['database']}-#{ts}.backup.sql"
|
90
|
+
path = File.join(rosie.backup_dir, ts, db_file)
|
91
|
+
args = get_db_cmdline_args
|
92
|
+
sh "mkdir -p #{rosie.backup_dir}/#{ts} && #{rosie.mysqldump_cmd} #{args.join(' ')} --single-transaction #{dbcnf['database']} > #{path}"
|
93
|
+
end
|
94
|
+
|
95
|
+
task :assets => :init do
|
96
|
+
sh "tar -C #{rosie.assets_dir} -cvf #{rosie.backup_dir}/#{ts}/rosie_backup_#{Rails.env}_#{ts}.tar ."
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
data/rosie.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require "rosie/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "rosie"
|
6
|
+
s.version = Rosie::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["Jon Rogers", "Jeremy Yun"]
|
9
|
+
s.email = ["j@2rye.com"]
|
10
|
+
s.homepage = "http://github.com/2rye/rosie"
|
11
|
+
s.summary = "rosie-#{Rosie::VERSION}"
|
12
|
+
s.description = %q{Backup/Restore MySQL database and dependent filesystem assets via rake tasks.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "rosie"
|
15
|
+
|
16
|
+
s.add_development_dependency('rspec')
|
17
|
+
s.add_development_dependency('rake', '~>0.9')
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rosie
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jon Rogers
|
9
|
+
- Jeremy Yun
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
|
14
|
+
date: 2011-08-19 00:00:00 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rspec
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
type: :development
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ~>
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "0.9"
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id002
|
38
|
+
description: Backup/Restore MySQL database and dependent filesystem assets via rake tasks.
|
39
|
+
email:
|
40
|
+
- j@2rye.com
|
41
|
+
executables: []
|
42
|
+
|
43
|
+
extensions: []
|
44
|
+
|
45
|
+
extra_rdoc_files: []
|
46
|
+
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- .rvmrc
|
50
|
+
- Gemfile
|
51
|
+
- Gemfile.lock
|
52
|
+
- LICENSE
|
53
|
+
- README.md
|
54
|
+
- lib/rosie.rb
|
55
|
+
- lib/rosie/version.rb
|
56
|
+
- lib/tasks/rosie.rake
|
57
|
+
- rosie.gemspec
|
58
|
+
homepage: http://github.com/2rye/rosie
|
59
|
+
licenses: []
|
60
|
+
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
requirements: []
|
79
|
+
|
80
|
+
rubyforge_project: rosie
|
81
|
+
rubygems_version: 1.8.8
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: rosie-0.0.1
|
85
|
+
test_files: []
|
86
|
+
|