cloud-backup 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/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/cloud-backup.gemspec +59 -0
- data/lib/cloud-backup.rb +15 -0
- data/lib/driver.rb +120 -0
- data/lib/driver_stack.rb +80 -0
- data/lib/drivers/log_backup_driver.rb +48 -0
- data/lib/drivers/rack_cloud_backup_driver.rb +53 -0
- data/lib/error.rb +18 -0
- data/test/helper.rb +10 -0
- data/test/test_cloud-backup.rb +7 -0
- metadata +96 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 kazuyoshi tlacaelel
|
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.rdoc
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
= cloud-backup
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
13
|
+
* Send me a pull request. Bonus points for topic branches.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2010 kazuyoshi tlacaelel. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "cloud-backup"
|
8
|
+
gem.summary = %Q{Backup to multiple cloud storage engines easily!}
|
9
|
+
gem.description = %Q{Backup to different clouds or create a driver and extend functionality!}
|
10
|
+
gem.email = "kazu.dev@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/ktlacaelel/cloud-backup"
|
12
|
+
gem.authors = ["kazuyoshi tlacaelel"]
|
13
|
+
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
Rake::TestTask.new(:test) do |test|
|
23
|
+
test.libs << 'lib' << 'test'
|
24
|
+
test.pattern = 'test/**/test_*.rb'
|
25
|
+
test.verbose = true
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'rcov/rcovtask'
|
30
|
+
Rcov::RcovTask.new do |test|
|
31
|
+
test.libs << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
task :rcov do
|
37
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
task :test => :check_dependencies
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "cloud-backup #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{cloud-backup}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["kazuyoshi tlacaelel"]
|
12
|
+
s.date = %q{2010-07-14}
|
13
|
+
s.description = %q{Backup to different clouds or create a driver and extend functionality!}
|
14
|
+
s.email = %q{kazu.dev@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"cloud-backup.gemspec",
|
27
|
+
"lib/cloud-backup.rb",
|
28
|
+
"lib/driver.rb",
|
29
|
+
"lib/driver_stack.rb",
|
30
|
+
"lib/drivers/log_backup_driver.rb",
|
31
|
+
"lib/drivers/rack_cloud_backup_driver.rb",
|
32
|
+
"lib/error.rb",
|
33
|
+
"test/helper.rb",
|
34
|
+
"test/test_cloud-backup.rb"
|
35
|
+
]
|
36
|
+
s.homepage = %q{http://github.com/ktlacaelel/cloud-backup}
|
37
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
38
|
+
s.require_paths = ["lib"]
|
39
|
+
s.rubygems_version = %q{1.3.7}
|
40
|
+
s.summary = %q{Backup to multiple cloud storage engines easily!}
|
41
|
+
s.test_files = [
|
42
|
+
"test/helper.rb",
|
43
|
+
"test/test_cloud-backup.rb"
|
44
|
+
]
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
48
|
+
s.specification_version = 3
|
49
|
+
|
50
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
51
|
+
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
52
|
+
else
|
53
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
54
|
+
end
|
55
|
+
else
|
56
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
data/lib/cloud-backup.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
# External but loaded from drivers
|
3
|
+
#
|
4
|
+
# - 'cloudfiles'
|
5
|
+
|
6
|
+
|
7
|
+
# Internal.
|
8
|
+
require 'driver'
|
9
|
+
require 'driver_stack'
|
10
|
+
require 'error'
|
11
|
+
|
12
|
+
# TODO: Create some sort of factory for drivers
|
13
|
+
require 'drivers/log_backup_driver'
|
14
|
+
require 'drivers/rack_cloud_backup_driver'
|
15
|
+
|
data/lib/driver.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
module CloudBackup
|
2
|
+
|
3
|
+
# Abstract driver for cloud-backups.
|
4
|
+
#
|
5
|
+
# This class is thought as an interface, it encapsulates the
|
6
|
+
# abstract logic of a backup and let's child-classes *drivers*
|
7
|
+
# implement the details of how to communicate to a specific storage
|
8
|
+
# engine.
|
9
|
+
#
|
10
|
+
class Driver
|
11
|
+
|
12
|
+
# Driver Initializer
|
13
|
+
#
|
14
|
+
# Each driver will probably have different parameters, api-keys
|
15
|
+
# authentication methods etc.
|
16
|
+
#
|
17
|
+
# Thus, initialization must be handled/implemented by child classes
|
18
|
+
#
|
19
|
+
def initialize
|
20
|
+
raise Error.must_define :initialize
|
21
|
+
end
|
22
|
+
|
23
|
+
# Initiate backup
|
24
|
+
#
|
25
|
+
# This callback is reserved to initiate server connections or
|
26
|
+
# specific per-driver initialization.
|
27
|
+
#
|
28
|
+
def initiate
|
29
|
+
raise Error.must_define :initiate
|
30
|
+
end
|
31
|
+
|
32
|
+
# Driver Identificator
|
33
|
+
#
|
34
|
+
# Specifies the *identificator* where the resources will be
|
35
|
+
# installed.
|
36
|
+
#
|
37
|
+
# For example: If you are storing data into Google-Storage, or
|
38
|
+
# S3 this could be a bucket-name.
|
39
|
+
#
|
40
|
+
# Note: each driver may specify different types of identificators
|
41
|
+
# or implement it's own methods depending on the storage-engine
|
42
|
+
# that is being used.
|
43
|
+
#
|
44
|
+
def identificator
|
45
|
+
raise Error.must_define :identificator
|
46
|
+
end
|
47
|
+
|
48
|
+
# Identificator changer
|
49
|
+
#
|
50
|
+
# Allows the client to change the identificator
|
51
|
+
#
|
52
|
+
def identificator name
|
53
|
+
raise Error.must_define :identificator=
|
54
|
+
end
|
55
|
+
|
56
|
+
# File aggregator
|
57
|
+
#
|
58
|
+
# Adds a file to be backed up by the driver, path might be an
|
59
|
+
# *absolute* or *relative* depending on how you are running your
|
60
|
+
# script.
|
61
|
+
#
|
62
|
+
# *absolute* paths are recommendend
|
63
|
+
#
|
64
|
+
def add_file path
|
65
|
+
@files ||= []
|
66
|
+
@files << path
|
67
|
+
end
|
68
|
+
|
69
|
+
# Uncommited files
|
70
|
+
#
|
71
|
+
# Returns a list of files that have not been backed up, but were
|
72
|
+
# passed by the *add_file* method. to be backed-up!
|
73
|
+
#
|
74
|
+
def list
|
75
|
+
@files ||= []
|
76
|
+
end
|
77
|
+
|
78
|
+
# Lists backed-up files ordered by date.
|
79
|
+
#
|
80
|
+
# Must return a list of all files that exist in the *Remote-Storage-Engine*
|
81
|
+
# as an array, ordered by date!
|
82
|
+
#
|
83
|
+
# Note: (FIFO)
|
84
|
+
#
|
85
|
+
def list_by_date
|
86
|
+
raise Error.must_define :list_by_date
|
87
|
+
end
|
88
|
+
|
89
|
+
# Remote resource remover
|
90
|
+
#
|
91
|
+
# Deletes a remote resource, normally this is thought to remove
|
92
|
+
# resources after new ones are beinng added
|
93
|
+
#
|
94
|
+
def remove name
|
95
|
+
raise Error.must_define :remove
|
96
|
+
end
|
97
|
+
|
98
|
+
# File uploader.
|
99
|
+
#
|
100
|
+
# Uploads all files that were added to the *queue*
|
101
|
+
#
|
102
|
+
def upload
|
103
|
+
raise Error.must_define :upload
|
104
|
+
end
|
105
|
+
|
106
|
+
# Termination callback
|
107
|
+
#
|
108
|
+
# This method is called after all other methods are called, right
|
109
|
+
# before terminating execution. You might wana use this to close
|
110
|
+
# connections to remote servers.
|
111
|
+
#
|
112
|
+
# Also. Good for notifications!
|
113
|
+
#
|
114
|
+
def terminate
|
115
|
+
raise Error.must_define :terminate
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
data/lib/driver_stack.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
module CloudBackup
|
2
|
+
|
3
|
+
class DriverStack
|
4
|
+
|
5
|
+
attr_accessor :max_items
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@list = []
|
9
|
+
@max_items = 2
|
10
|
+
@file_names = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def list
|
14
|
+
@list
|
15
|
+
end
|
16
|
+
|
17
|
+
def addable? driver
|
18
|
+
driver.is_a? CloudBackup::Driver
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_driver konstant
|
22
|
+
@list << konstant
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_file name
|
26
|
+
@file_names << name
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_files array
|
30
|
+
@file_names = @file_names + array
|
31
|
+
end
|
32
|
+
|
33
|
+
def perform_backup!
|
34
|
+
driver_initiate
|
35
|
+
driver_add_files
|
36
|
+
driver_upload_files
|
37
|
+
driver_remove_old_files
|
38
|
+
driver_shut_down_execution
|
39
|
+
end
|
40
|
+
|
41
|
+
def driver_initiate
|
42
|
+
@list.each do |driver|
|
43
|
+
driver.initiate
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
def driver_add_files
|
50
|
+
@list.each do |driver|
|
51
|
+
@file_names.each do |file_name|
|
52
|
+
driver.add_file file_name
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def driver_upload_files
|
58
|
+
@list.each do |driver|
|
59
|
+
driver.upload
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def driver_remove_old_files
|
64
|
+
@list.each do |driver|
|
65
|
+
names = driver.list_by_date
|
66
|
+
(names - names.first(@max_items)).each do |name|
|
67
|
+
driver.remove name
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def driver_shut_down_execution
|
73
|
+
@list.each do |driver|
|
74
|
+
driver.terminate
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class LogBackupDriver < CloudBackup::Driver
|
2
|
+
|
3
|
+
def initialize stream
|
4
|
+
@stream = stream
|
5
|
+
end
|
6
|
+
|
7
|
+
def initiate
|
8
|
+
output 'Initiating execution'
|
9
|
+
end
|
10
|
+
|
11
|
+
def identificator
|
12
|
+
@identificator
|
13
|
+
end
|
14
|
+
|
15
|
+
def identificator= name
|
16
|
+
@identificator = name
|
17
|
+
end
|
18
|
+
|
19
|
+
def list_by_date
|
20
|
+
output 'Listing driver items by date'
|
21
|
+
list.each do |file|
|
22
|
+
output "Listing.. file: #{file}"
|
23
|
+
end
|
24
|
+
@list ||= list
|
25
|
+
end
|
26
|
+
|
27
|
+
def remove name
|
28
|
+
@list = @list - [name]
|
29
|
+
output "Removing item: #{name}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def upload
|
33
|
+
list.each do |file|
|
34
|
+
output "Uploading.. file: #{file}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def terminate
|
39
|
+
output 'Terminating execution'
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def output data
|
45
|
+
@stream.puts data
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'cloudfiles'
|
2
|
+
|
3
|
+
class RackCloudBackupDriver < CloudBackup::Driver
|
4
|
+
|
5
|
+
def initialize credentials
|
6
|
+
@id = credentials[:id]
|
7
|
+
@key = credentials[:key]
|
8
|
+
@cf = CloudFiles::Connection.new(@id, @key)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initiate
|
12
|
+
@bucket = get_or_create_bucket
|
13
|
+
end
|
14
|
+
|
15
|
+
def identificator
|
16
|
+
@identificator
|
17
|
+
end
|
18
|
+
|
19
|
+
def identificator= name
|
20
|
+
@identificator = name
|
21
|
+
end
|
22
|
+
|
23
|
+
# TODO: parse metadata
|
24
|
+
def list_by_date
|
25
|
+
@bucket.objects
|
26
|
+
end
|
27
|
+
|
28
|
+
def remove name
|
29
|
+
@bucket.delete_object name
|
30
|
+
end
|
31
|
+
|
32
|
+
# TODO: set metadata to objects
|
33
|
+
def upload
|
34
|
+
list.each do |file|
|
35
|
+
object = @bucket.create_object File.basename(file)
|
36
|
+
object.write File.read(file)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def terminate
|
41
|
+
@cf, @bucket = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def get_or_create_bucket
|
47
|
+
unless @cf.containers.include? identificator
|
48
|
+
@cf.create_container identificator
|
49
|
+
end
|
50
|
+
@cf.container identificator
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/lib/error.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module CloudBackup
|
2
|
+
|
3
|
+
class Error < Exception
|
4
|
+
end
|
5
|
+
|
6
|
+
class << Error
|
7
|
+
|
8
|
+
def must_define(method)
|
9
|
+
new "You must define a (#{method}) method in your driver class."
|
10
|
+
end
|
11
|
+
|
12
|
+
def invalid_identificator
|
13
|
+
new 'Invalid identificator.'
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/test/helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cloud-backup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- kazuyoshi tlacaelel
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-07-14 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: thoughtbot-shoulda
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
description: Backup to different clouds or create a driver and extend functionality!
|
36
|
+
email: kazu.dev@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.rdoc
|
44
|
+
files:
|
45
|
+
- .document
|
46
|
+
- .gitignore
|
47
|
+
- LICENSE
|
48
|
+
- README.rdoc
|
49
|
+
- Rakefile
|
50
|
+
- VERSION
|
51
|
+
- cloud-backup.gemspec
|
52
|
+
- lib/cloud-backup.rb
|
53
|
+
- lib/driver.rb
|
54
|
+
- lib/driver_stack.rb
|
55
|
+
- lib/drivers/log_backup_driver.rb
|
56
|
+
- lib/drivers/rack_cloud_backup_driver.rb
|
57
|
+
- lib/error.rb
|
58
|
+
- test/helper.rb
|
59
|
+
- test/test_cloud-backup.rb
|
60
|
+
has_rdoc: true
|
61
|
+
homepage: http://github.com/ktlacaelel/cloud-backup
|
62
|
+
licenses: []
|
63
|
+
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options:
|
66
|
+
- --charset=UTF-8
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
hash: 3
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
hash: 3
|
84
|
+
segments:
|
85
|
+
- 0
|
86
|
+
version: "0"
|
87
|
+
requirements: []
|
88
|
+
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 1.3.7
|
91
|
+
signing_key:
|
92
|
+
specification_version: 3
|
93
|
+
summary: Backup to multiple cloud storage engines easily!
|
94
|
+
test_files:
|
95
|
+
- test/helper.rb
|
96
|
+
- test/test_cloud-backup.rb
|