jemmyw-backs3 0.0.1

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/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
+