jemmyw-backs3 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
File without changes
data/Manifest.txt ADDED
@@ -0,0 +1,17 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ example.conf
6
+ bin/backs3
7
+ bin/res3
8
+ lib/backs3.rb
9
+ lib/backs3/backs3.rb
10
+ lib/backs3/backup.rb
11
+ lib/backs3/restore.rb
12
+ lib/backs3/version.rb
13
+ spec/spec.opts
14
+ spec/spec_helper.rb
15
+ spec/backs3/backup_spec.rb
16
+ spec/backs3/restore_spec.rb
17
+ tasks/rspec.rake
data/README.txt ADDED
@@ -0,0 +1,51 @@
1
+ = Backs3
2
+
3
+ * http://github.com/jemmyw/backs3
4
+
5
+ == DESCRIPTION:
6
+
7
+ A simple backup and restore program for S3
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * FIX (list of features or problems)
12
+
13
+ == SYNOPSIS:
14
+
15
+ backs3 -c s3.conf test
16
+ res3 -c s3.conf available => [12345, 54321]
17
+ res3 -c s3.conf restore 12345
18
+
19
+ == REQUIREMENTS:
20
+
21
+ * ActiveSupport
22
+ * AWS/S3
23
+
24
+ == INSTALL:
25
+
26
+ * sudo gem install jemmyw-backs3
27
+
28
+ == LICENSE:
29
+
30
+ (The MIT License)
31
+
32
+ Copyright (c) 2009 Jeremy Wells / Boost Limited
33
+
34
+ Permission is hereby granted, free of charge, to any person obtaining
35
+ a copy of this software and associated documentation files (the
36
+ 'Software'), to deal in the Software without restriction, including
37
+ without limitation the rights to use, copy, modify, merge, publish,
38
+ distribute, sublicense, and/or sell copies of the Software, and to
39
+ permit persons to whom the Software is furnished to do so, subject to
40
+ the following conditions:
41
+
42
+ The above copyright notice and this permission notice shall be
43
+ included in all copies or substantial portions of the Software.
44
+
45
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
46
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
47
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
48
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
49
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
50
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
51
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
data/bin/backs3 ADDED
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'rubygems'
5
+ require 'backs3/backup'
6
+ rescue LoadError => e
7
+ require 'lib/backs3/backup'
8
+ end
9
+
10
+ require 'active_support'
11
+ require 'getoptlong'
12
+
13
+ option_parser = GetoptLong.new(
14
+ ['--help', '-h', GetoptLong::NO_ARGUMENT],
15
+ ['--config', '-c', GetoptLong::REQUIRED_ARGUMENT],
16
+ ['--exclude', GetoptLong::REQUIRED_ARGUMENT],
17
+ ['--id', '-i', GetoptLong::REQUIRED_ARGUMENT],
18
+ ['--key', '-k', GetoptLong::REQUIRED_ARGUMENT],
19
+ ['--bucket', '-b', GetoptLong::REQUIRED_ARGUMENT],
20
+ ['--prefix', '-p', GetoptLong::REQUIRED_ARGUMENT],
21
+ ['--full', '-f', GetoptLong::REQUIRED_ARGUMENT],
22
+ ['--force-full', GetoptLong::NO_ARGUMENT]
23
+ )
24
+
25
+ $options = {}
26
+
27
+ def usage(message = nil)
28
+ $stderr.puts message unless message.blank?
29
+
30
+ name = $0.split('/').last
31
+ $stderr.puts <<"ENDUSAGE"
32
+ #{name} [options] <directory>
33
+ --help -h
34
+ --config -c Configuration file
35
+ --id -i AWS Access Key ID
36
+ --key -k AWS Secret Key
37
+ --bucket -b AWS Bucket name
38
+ --full=d -f d Number of days between full backups (default: 7)
39
+ --force-full Force a full backup
40
+ --prefix -p
41
+ --exclude="regex" Exclude files based on regex
42
+
43
+ ENDUSAGE
44
+
45
+ $stderr.puts "Current configuration:"
46
+ $options.each do |key, value|
47
+ $stderr.puts " #{key}: \t#{value}"
48
+ end
49
+
50
+ exit!
51
+ end #usage
52
+
53
+ begin
54
+ option_parser.each do |opt, arg|
55
+ $options[opt.gsub(/^-*/, '')] = (arg || true)
56
+ end
57
+
58
+ usage if $options['help']
59
+ $options['folder'] = ARGV[0] unless ARGV[0].blank?
60
+
61
+ raise Exception.new("Invalid configuration file #{$options['config']}") unless $options['config'].blank? || File.exists?($options['config'])
62
+ $options['config'] ||= '/etc/backs3.conf'
63
+
64
+ if File.exists?($options['config'])
65
+ begin
66
+ puts "Reading configuration from #{$options['config']}"
67
+ config = YAML::load_file($options['config'])
68
+ $options = config.merge($options)
69
+ rescue
70
+ raise Exception.new("Invalid configuration file #{$options['config']}")
71
+ end
72
+ end
73
+
74
+ raise Exception.new("You must specify a directory to backup") if $options['folder'].blank?
75
+ raise Exception.new("You must specify a bucket") if $options['bucket'].blank?
76
+ raise Exception.new("You must specify an AWS ID") if $options['id'].blank?
77
+ raise Exception.new("You must specify an AWS Secret Key") if $options['key'].blank?
78
+ rescue Exception => e
79
+ usage(e.to_s)
80
+ end
81
+
82
+ backs3 = Backs3::Backup.new($options)
83
+ backs3.backup
data/bin/res3 ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'rubygems'
5
+ require 'backs3/restore'
6
+ rescue LoadError => e
7
+ require 'lib/backs3/restore'
8
+ end
9
+
10
+ require 'active_support'
11
+ require 'getoptlong'
12
+
13
+ option_parser = GetoptLong.new(
14
+ ['--help', '-h', GetoptLong::NO_ARGUMENT],
15
+ ['--config', '-c', GetoptLong::REQUIRED_ARGUMENT],
16
+ ['--id', '-i', GetoptLong::REQUIRED_ARGUMENT],
17
+ ['--key', '-k', GetoptLong::REQUIRED_ARGUMENT],
18
+ ['--bucket', '-b', GetoptLong::REQUIRED_ARGUMENT],
19
+ ['--prefix', '-p', GetoptLong::REQUIRED_ARGUMENT]
20
+ )
21
+
22
+ $options = {}
23
+
24
+ def usage(message = nil)
25
+ $stderr.puts message unless message.blank?
26
+
27
+ name = $0.split('/').last
28
+ $stderr.puts <<"ENDUSAGE"
29
+ #{name} [options] <directory> <command> [command options]
30
+ Commands:
31
+ #{Backs3::Restore.commands.join(", ")}
32
+
33
+ --help -h
34
+ --config -c Configuration file
35
+ --id -i AWS Access Key ID
36
+ --key -k AWS Secret Key
37
+ --bucket -b AWS Bucket name
38
+ --prefix -p
39
+
40
+ ENDUSAGE
41
+
42
+ $stderr.puts "Current configuration:"
43
+ $options.each do |key, value|
44
+ $stderr.puts " #{key}: \t#{value}"
45
+ end
46
+
47
+ exit!
48
+ end #usage
49
+
50
+ begin
51
+ option_parser.each do |opt, arg|
52
+ $options[opt.gsub(/^-*/, '')] = (arg || true)
53
+ end
54
+
55
+ usage if $options['help']
56
+
57
+ raise Exception.new("Invalid configuration file #{$options['config']}") unless $options['config'].blank? || File.exists?($options['config'])
58
+ $options['config'] ||= '/etc/backs3.conf'
59
+
60
+ if File.exists?($options['config'])
61
+ begin
62
+ puts "Reading configuration from #{$options['config']}"
63
+ config = YAML::load_file($options['config'])
64
+ $options = config.merge($options)
65
+ rescue
66
+ raise Exception.new("Invalid configuration file #{$options['config']}")
67
+ end
68
+ end
69
+
70
+ args = ARGV
71
+ $options['folder'] = args.shift if $options['folder'].blank?
72
+ $command = args.shift
73
+
74
+ raise Exception.new("You must specify a directory to restore from") if $options['folder'].blank?
75
+ raise Exception.new("You must specify a bucket") if $options['bucket'].blank?
76
+ raise Exception.new("You must specify an AWS ID") if $options['id'].blank?
77
+ raise Exception.new("You must specify an AWS Secret Key") if $options['key'].blank?
78
+ raise Exception.new("You must specify a valid command") unless Backs3::Restore.commands.include?($command)
79
+ rescue Exception => e
80
+ usage(e.to_s)
81
+ end
82
+
83
+ res3 = Backs3::Restore.new($options)
84
+ res3.send($command, *args)
data/example.conf ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ id: xxx
3
+ key: xxx
4
+ folder: xxx
5
+ bucket: xxx
@@ -0,0 +1,39 @@
1
+ # #!/usr/bin/env ruby
2
+
3
+ require 'rubygems' rescue nil
4
+ require 'aws/s3'
5
+ require 'active_support'
6
+ require 'digest/md5'
7
+ require 'time'
8
+
9
+ $has_md5 = !(`which md5`).blank?
10
+
11
+ module Backs3
12
+ include AWS::S3
13
+
14
+ def establish_connection
15
+ AWS::S3::Base.establish_connection!(
16
+ :access_key_id => @options['id'],
17
+ :secret_access_key => @options['key']
18
+ )
19
+ end
20
+
21
+ def md5(filename)
22
+ if $has_md5
23
+ `md5 #{filename}`
24
+ else
25
+ Digest::MD5.hexdigest(filename)
26
+ end
27
+ end
28
+
29
+ def backup_info
30
+ @backup_info ||= begin
31
+ backup_info_file = S3Object.find(@options['prefix'] + 's3backup', @options['bucket'])
32
+ backup_info_data = backup_info_file.value(:reload)
33
+ YAML.load(backup_info_data) || {}
34
+ rescue Exception => e
35
+ puts e.to_s
36
+ {}
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,82 @@
1
+ require File.dirname(__FILE__) + '/backs3'
2
+
3
+ module Backs3
4
+ class Backup
5
+ include Backs3
6
+ include AWS::S3
7
+
8
+ def initialize(options = {})
9
+ @options = options
10
+ @options['prefix'] ||= ''
11
+ end
12
+
13
+ def first_backup?
14
+ last_backup.nil?
15
+ end
16
+
17
+ def full_backup
18
+ @options['force-full'] || first_backup? || Time.now.to_i - last_backup > (@options['full'] || 7).days
19
+ end
20
+
21
+ def last_backup
22
+ backup_info['last_backup'].to_i
23
+ end
24
+
25
+ def backup_key
26
+ @options['prefix'] + @current_backup
27
+ end
28
+
29
+ def last_key
30
+ @options['prefix'] + last_backup.to_s
31
+ end
32
+
33
+ def files_to_backup
34
+ @files_to_backup ||= begin
35
+ Dir.glob(File.join(@options['folder'], '**', '**')).select do |file|
36
+ if @options['exclude'].blank? || file !~ /#{@options['exclude']}/
37
+ if full_backup || File.mtime(file).to_i > last_backup
38
+ true
39
+ else
40
+ false
41
+ end
42
+ else
43
+ false
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ def backup
50
+ @current_backup = Time.now.to_i.to_s
51
+ @files_to_backup = nil
52
+ @backup_info = nil
53
+
54
+ establish_connection
55
+
56
+ puts "Backup started at #{Time.now}"
57
+ puts "Last backup happened at #{backup_info['last_backup']}"
58
+ puts "Performing %s" % (full_backup ? "full backup" : "incremental backup")
59
+
60
+ files_to_backup.each do |filename|
61
+ puts "Backing up #{filename}"
62
+ file_md5 = md5(filename)
63
+ aws_filename = File.join(backup_key, filename)
64
+
65
+ object = S3Object.find(aws_filename, @options['bucket']) rescue nil
66
+
67
+ if object.nil? || object.metadata[:md5sum] != file_md5
68
+ S3Object.store(aws_filename, open(filename), @options['bucket'])
69
+ object = S3Object.find(aws_filename, @options['bucket'])
70
+ object.metadata[:md5sum] = file_md5
71
+ object.save
72
+ end
73
+ end
74
+
75
+ backup_info['last_backup'] = @current_backup
76
+ backup_info['backups'] ||= []
77
+ backup_info['backups'] << @current_backup
78
+ S3Object.store(@options['prefix'] + 's3backup', YAML.dump(backup_info), @options['bucket'])
79
+ puts "Backup completed, #{files_to_backup.size} files backed up"
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,89 @@
1
+ require File.dirname(__FILE__) + '/backs3'
2
+ require 'fileutils'
3
+
4
+ module Backs3
5
+ class Restore
6
+ include Backs3
7
+ include AWS::S3
8
+
9
+ def self.commands
10
+ %w(ls available restore cat)
11
+ end
12
+
13
+ def initialize(options = {})
14
+ @options = options
15
+ @options['prefix'] ||= ''
16
+ establish_connection
17
+ end
18
+
19
+ def available(file = nil)
20
+ if file.nil?
21
+ puts "Backups available: #{backup_info['backups'].join(", ")}"
22
+ else
23
+ info = backup_info['backups'].collect do |backup|
24
+ backup_key = @options['prefix'] + backup.to_s
25
+ object = S3Object.find(File.join(backup_key, file), @options['bucket']) rescue nil
26
+
27
+ if object
28
+ {
29
+ :backup => backup,
30
+ :md5 => object.metadata[:md5sum]
31
+ }
32
+ else
33
+ nil
34
+ end
35
+
36
+ end.compact
37
+
38
+ puts "Backup information for #{file}:"
39
+ info.each do |i|
40
+ puts "\tBackup #{i[:backup]}: #{i[:md5]}"
41
+ end
42
+
43
+ end
44
+ end
45
+
46
+ def ls(backup)
47
+ Bucket.objects(@options['bucket'], :prefix => @options['prefix'] + backup.to_s).each do |object|
48
+ puts object.key
49
+ end
50
+ end
51
+
52
+ def cat(backup, file)
53
+ backup_key = @options['prefix'] + backup.to_s
54
+ object = S3Object.find(File.join(backup_key, file), @options['bucket']) rescue nil
55
+
56
+ if object.nil?
57
+ puts "Cannot find file #{file}"
58
+ else
59
+ puts object.value(:reload)
60
+ end
61
+ end
62
+
63
+ def restore(backup, file = nil)
64
+ backup_key = @options['prefix'] + backup.to_s
65
+ objects = []
66
+
67
+ if file.nil?
68
+ objects = Bucket.objects(@options['bucket'], :prefix => @options['prefix'] + backup.to_s)
69
+ else
70
+ objects << S3Object.find(File.join(backup_key, file), @options['bucket']) rescue nil
71
+ end
72
+
73
+ objects.compact!
74
+
75
+ objects.each do |object|
76
+ $stdout.write "Restoring file #{object.key} to /tmp/#{object.key}"
77
+ filename = "/tmp/#{object.key}"
78
+ FileUtils.mkdir_p File.dirname(filename)
79
+ File.open(filename, 'w') do |f|
80
+ object.value do |segment|
81
+ $stdout.write "."
82
+ f.write segment
83
+ end
84
+ end
85
+ $stdout.write "\n"
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,9 @@
1
+ module Backs3 #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
data/lib/backs3.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + '/backs3/backs3'
@@ -0,0 +1,73 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require 'backs3/backup'
3
+ include Backs3
4
+
5
+ describe Backup do
6
+ before(:each) do
7
+ AWS::S3::Base.stub!(:establish_connection!)
8
+ @bucket = 'test_bucket'
9
+ @backup = Backup.new({'bucket' => @bucket})
10
+ end
11
+
12
+ describe 'backup' do
13
+ it 'should backup all the files returned by files_to_backup'
14
+ end
15
+
16
+ describe 'first_backup?' do
17
+ it 'should be true if there is no previous backup' do
18
+ @backup.should_receive(:last_backup).and_return(nil)
19
+ @backup.first_backup?.should be_true
20
+ end
21
+
22
+ it 'should be false if there is a previous backup' do
23
+ @backup.should_receive(:last_backup).and_return(12345)
24
+ @backup.first_backup?.should be_false
25
+ end
26
+ end
27
+
28
+ describe 'full_backup' do
29
+ it 'should be true if force-full option is set' do
30
+ @backup = Backup.new('force-full' => true)
31
+ @backup.should_not_receive(:last_backup)
32
+ @backup.should_not_receive(:first_backup?)
33
+ @backup.full_backup.should be_true
34
+ end
35
+ it 'should be true if this is the first backup' do
36
+ @backup.should_receive(:first_backup?).and_return(true)
37
+ @backup.full_backup.should be_true
38
+ end
39
+ it 'should be true if the last backup was more than 7 days ago' do
40
+ @backup.should_receive(:first_backup?).and_return(false)
41
+ @backup.should_receive(:last_backup).and_return((Time.now - 8.days).to_i)
42
+ @backup.full_backup.should be_true
43
+ end
44
+ it 'should be false' do
45
+ @backup.should_receive(:first_backup?).and_return(false)
46
+ @backup.should_receive(:last_backup).and_return(Time.now.to_i)
47
+ @backup.full_backup.should be_false
48
+ end
49
+ end
50
+
51
+ describe 'last_backup' do
52
+ it 'should return the integer time of the last backup' do
53
+ time = Time.now
54
+ time.should_receive(:to_i).and_return(12345)
55
+ @backup.should_receive(:backup_info).and_return({'last_backup' => time})
56
+ @backup.last_backup.should == 12345
57
+ end
58
+ end
59
+
60
+ describe 'backup_key' do
61
+ it 'should return the prefix + the backup time'
62
+ end
63
+
64
+ describe 'last_key' do
65
+ it 'should return the prefix + the last backup time'
66
+ end
67
+
68
+ describe 'files_to_backup' do
69
+ it 'should return all the files in the backup folder'
70
+ it 'should not return excluded files'
71
+ it 'should not return files that have not changed if this is an incremental backup'
72
+ end
73
+ end
@@ -0,0 +1,54 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require 'backs3/restore'
3
+
4
+ include Backs3
5
+
6
+ describe Restore do
7
+ before(:each) do
8
+ AWS::S3::Base.stub!(:establish_connection!)
9
+ @bucket = 'test_bucket'
10
+ @restore = Restore.new('bucket' => @bucket)
11
+
12
+ @file_1 = mock(:s3object, :metadata => {})
13
+ end
14
+
15
+ describe 'self.commands' do
16
+ it 'should return an array' do
17
+ Restore.commands.should be_a(Array)
18
+ end
19
+ end
20
+
21
+ describe 'available' do
22
+ it 'should list all of the backups available if no file is specified' do
23
+ @restore.should_receive(:backup_info).and_return({'backups' => [12345, 54321]})
24
+ @restore.should_receive(:puts).with('Backups available: 12345, 54321')
25
+ @restore.available
26
+ end
27
+ it 'should list all of the backups a file is in' do
28
+ file = 'test/file_1'
29
+ @restore.should_receive(:backup_info).and_return({'backups' => [12345, 54321]})
30
+ S3Object.should_receive(:find).with('12345/test/file_1', @bucket).and_return(@file_1)
31
+ S3Object.should_receive(:find).with('54321/test/file_1', @bucket).and_return(nil)
32
+
33
+ @restore.should_receive(:puts).with('Backup information for test/file_1:')
34
+ @restore.should_receive(:puts).with("\tBackup 12345: ")
35
+ @restore.should_not_receive(:puts).with("\tBackup 54321: ")
36
+
37
+ @restore.available(file)
38
+ end
39
+ end
40
+
41
+ describe 'ls' do
42
+ it 'should list all of the files in a directory'
43
+ end
44
+
45
+ describe 'cat' do
46
+ it 'should show an error if the file specified does not exist'
47
+ it 'should output the contents of a file'
48
+ end
49
+
50
+ describe 'restore' do
51
+ it 'should restore a whole backup if no file is specified'
52
+ it 'should restore a file'
53
+ end
54
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,19 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'backs3'
11
+
12
+ include Spec::Matchers
13
+
14
+ module Kernel
15
+ def logger
16
+ @@__log_file__ ||= StringIO.new
17
+ @@__log__ = ActiveSupport::BufferedLogger.new @@__log_file__
18
+ end
19
+ end
data/tasks/rspec.rake ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jemmyw-backs3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Wells
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-25 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
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.2
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: aws-s3
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.5.1
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: hoe
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.8.0
44
+ version:
45
+ description: S3 backup and restore program
46
+ email:
47
+ - jeremy@boost.co.nz
48
+ executables:
49
+ - backs3
50
+ - res3
51
+ extensions: []
52
+
53
+ extra_rdoc_files:
54
+ - History.txt
55
+ - Manifest.txt
56
+ - README.txt
57
+ files:
58
+ - History.txt
59
+ - Manifest.txt
60
+ - README.txt
61
+ - Rakefile
62
+ - example.conf
63
+ - bin/backs3
64
+ - bin/res3
65
+ - lib/backs3.rb
66
+ - lib/backs3/backs3.rb
67
+ - lib/backs3/backup.rb
68
+ - lib/backs3/restore.rb
69
+ - lib/backs3/version.rb
70
+ - spec/spec.opts
71
+ - spec/spec_helper.rb
72
+ - spec/backs3/backup_spec.rb
73
+ - spec/backs3/restore_spec.rb
74
+ - tasks/rspec.rake
75
+ has_rdoc: true
76
+ homepage: http://backs3.rubyforge.org
77
+ post_install_message:
78
+ rdoc_options:
79
+ - --main
80
+ - README.txt
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: "0"
88
+ version:
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: "0"
94
+ version:
95
+ requirements: []
96
+
97
+ rubyforge_project: backs3
98
+ rubygems_version: 1.2.0
99
+ signing_key:
100
+ specification_version: 2
101
+ summary: S3 backup and restore program
102
+ test_files: []
103
+