encbs 0.1.3 → 0.2.0.alpha
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/Gemfile +2 -0
- data/VERSION +1 -1
- data/bin/encbs +208 -165
- data/encbs.gemspec +10 -3
- data/lib/archive.rb +32 -0
- data/lib/backup/file_item/base.rb +2 -4
- data/lib/backup/file_item/cloud.rb +9 -4
- data/lib/backup/file_item/local.rb +19 -5
- data/lib/backup/jar.rb +73 -45
- data/lib/backup.rb +40 -11
- data/lib/crypto.rb +12 -6
- data/lib/encbsconfig.rb +22 -10
- data/lib/helpers.rb +15 -10
- data/test/helper.rb +3 -0
- data/test/test_backup_file_item.rb +2 -10
- metadata +35 -12
data/Gemfile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0.alpha
|
data/bin/encbs
CHANGED
@@ -8,218 +8,261 @@ require 'fileutils'
|
|
8
8
|
require 'openssl'
|
9
9
|
require 'socket'
|
10
10
|
require 'helpers'
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
require 'slop'
|
12
|
+
require 'fog'
|
13
|
+
require 'progressbar'
|
14
|
+
require 'lzoruby'
|
15
|
+
require 'zlib'
|
16
|
+
require 'base64'
|
17
17
|
|
18
18
|
require 'backup'
|
19
19
|
require 'encbsconfig'
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
on :c, :config, "Use config file to upload backup", true
|
25
|
-
on :colorize, "Colorize print to console"
|
26
|
-
on :d, :date, "Date for backup restore (default: last)", true
|
27
|
-
on :g, :generate, "Generate RSA keys (option: 4096, 2048)", true
|
28
|
-
on :h, :hostname, "Set hostname (default: system)", true
|
29
|
-
on :i, :increment, "Use increment mode for backup (default: false)"
|
30
|
-
on :j, :jar, "Versions of jar (option: hash or path)", true
|
31
|
-
on :k, :key, "Set API key to access Amazon S3", true
|
32
|
-
on :l, :local, "Backup in local directory", true
|
33
|
-
on :list, "List of jars"
|
34
|
-
on :r, :rescue, "Return data from backup (option: jar, path or filter)", true
|
35
|
-
on :s, :secret, "Set API secret to access Amazon S3", true
|
36
|
-
on :t, :to, "Path to recovery (default: /)", true
|
37
|
-
on :token, "RSA Key to encrypt/decrypt backup data", true
|
38
|
-
on :v, :verbose, "Verbose mode"
|
39
|
-
|
40
|
-
banner "Usage:\n $ encbs [options]\n\nOptions:"
|
41
|
-
end
|
42
|
-
|
43
|
-
@config = EncbsConfig.new
|
44
|
-
|
45
|
-
if ARGV.empty?
|
46
|
-
if File.exists?("#{Dir.getwd}/Encbsfile")
|
47
|
-
@config.load "#{Dir.getwd}/Encbsfile"
|
21
|
+
begin
|
22
|
+
if lock_exists?
|
23
|
+
puts_fail "Lock file exists. Make sure that an encbs instance does not exists."
|
48
24
|
else
|
49
|
-
|
50
|
-
exit
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
@config.load opts[:config] if opts.config?
|
55
|
-
|
56
|
-
$PRINT_VERBOSE = @config.verbose || opts.verbose?
|
57
|
-
$COLORIZE = @config.colorize || opts.colorize?
|
58
|
-
|
59
|
-
if opts.generate?
|
60
|
-
bits = opts[:generate].to_i
|
61
|
-
puts_fail "Unsupport #{bits} bits" unless bits == 4096 or bits == 2048
|
62
|
-
puts "Generate #{bits} bits RSA keys"
|
63
|
-
Crypto::create_keys(
|
64
|
-
File.join(Dir.getwd, "rsa_key"),
|
65
|
-
File.join(Dir.getwd, "rsa_key.pub"),
|
66
|
-
bits
|
67
|
-
)
|
68
|
-
puts "Done!"
|
69
|
-
|
70
|
-
exit
|
71
|
-
end
|
72
|
-
|
73
|
-
if opts.local?
|
74
|
-
try_create_dir opts[:local]
|
75
|
-
@backup = Backup::Instance.new opts[:local]
|
76
|
-
else
|
77
|
-
[:key, :secret, :bucket].each do |arg|
|
78
|
-
if opts[arg].nil? and @config.send(arg).nil?
|
79
|
-
puts_fail "Argument '--#{arg}' should not be empty"
|
80
|
-
end
|
25
|
+
create_lock
|
81
26
|
end
|
82
|
-
|
83
|
-
|
84
|
-
true
|
85
|
-
:bucket
|
86
|
-
:
|
87
|
-
:
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
27
|
+
|
28
|
+
opts = Slop.parse :help => true do
|
29
|
+
on :a, :add, "Add path to backup", true
|
30
|
+
on :b, :bucket, "Set Amazon S3 bucket to backup", true
|
31
|
+
on :c, :config, "Use config file to upload backup", true
|
32
|
+
on :colorize, "Colorize print to console"
|
33
|
+
on :compression, "Use gzip for file (de)compression (option: gzip, lzo)", true
|
34
|
+
on :d, :date, "Date for backup restore (default: last)", true
|
35
|
+
on :g, :generate, "Generate RSA keys (option: 4096, 2048)", true
|
36
|
+
on :h, :hostname, "Set hostname (default: system)", true
|
37
|
+
on :i, :increment, "Use increment mode for backup (default: false)"
|
38
|
+
on :j, :jar, "Versions of jar (option: hash or path)", true
|
39
|
+
on :k, :key, "Set API key to access Amazon S3", true
|
40
|
+
on :l, :local, "Backup in local directory", true
|
41
|
+
on :list, "List of jars"
|
42
|
+
on :r, :rescue, "Return data from backup (option: jar, path or filter)", true
|
43
|
+
on :s, :secret, "Set API secret to access Amazon S3", true
|
44
|
+
on :t, :to, "Path to recovery (default: /)", true
|
45
|
+
on :timeout, "Timeout(sec) to try pushing into cloud (default: 60s)", true
|
46
|
+
on :token, "RSA key to encrypt/decrypt backup data", true
|
47
|
+
on :size, "RSA private key length (default: 4096)", true
|
48
|
+
on :v, :verbose, "Verbose mode"
|
49
|
+
|
50
|
+
banner "Usage:\n $ encbs [options]\n\nOptions:"
|
103
51
|
end
|
104
52
|
|
105
|
-
|
106
|
-
end
|
53
|
+
@config = EncbsConfig.new
|
107
54
|
|
108
|
-
if
|
109
|
-
|
55
|
+
if ARGV.empty?
|
56
|
+
if File.exists?("#{Dir.getwd}/Encbsfile")
|
57
|
+
@config.load "#{Dir.getwd}/Encbsfile"
|
58
|
+
else
|
59
|
+
puts opts.help
|
60
|
+
exit
|
61
|
+
end
|
62
|
+
end
|
110
63
|
|
111
|
-
|
64
|
+
@config.load opts[:config] if opts.config?
|
112
65
|
|
113
|
-
@
|
114
|
-
|
66
|
+
$PRINT_VERBOSE = @config.verbose || opts.verbose?
|
67
|
+
$COLORIZE = @config.colorize || opts.colorize?
|
115
68
|
|
116
|
-
if opts.
|
117
|
-
|
69
|
+
if opts.generate?
|
70
|
+
bits = opts[:generate].to_i
|
71
|
+
puts_fail "Unsupport #{bits} bits" unless bits == 4096 or bits == 2048
|
72
|
+
puts "Generate #{bits} bits RSA keys"
|
73
|
+
Crypto::create_keys(
|
74
|
+
File.join(Dir.getwd, "rsa_key"),
|
75
|
+
File.join(Dir.getwd, "rsa_key.pub"),
|
76
|
+
bits
|
77
|
+
)
|
78
|
+
puts "Done!"
|
118
79
|
|
119
|
-
|
120
|
-
|
121
|
-
@end_date = Backup::Timestamp.parse_timestamp date[1], true
|
80
|
+
exit
|
81
|
+
end
|
122
82
|
|
123
|
-
|
83
|
+
if opts.local?
|
84
|
+
try_create_dir opts[:local]
|
85
|
+
@backup = Backup::Instance.new opts[:local]
|
124
86
|
else
|
125
|
-
|
126
|
-
|
87
|
+
[:key, :secret, :bucket].each do |arg|
|
88
|
+
if opts[arg].nil? and @config.send(arg).nil?
|
89
|
+
puts_fail "Argument '--#{arg}' should not be empty"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
@backup = Backup::Instance.new(
|
93
|
+
"backups",
|
94
|
+
true,
|
95
|
+
:bucket => @config.bucket || opts[:bucket],
|
96
|
+
:key => @config.key || opts[:key],
|
97
|
+
:secret => @config.secret || opts[:secret]
|
98
|
+
)
|
127
99
|
end
|
128
|
-
else
|
129
|
-
@start_date = nil
|
130
|
-
@end_date = Time.now.utc
|
131
|
-
end
|
132
100
|
|
133
|
-
if opts.
|
134
|
-
|
135
|
-
|
101
|
+
hostname = @config.hostname || opts[:hostname] if opts.hostname?
|
102
|
+
@backup.hostname = hostname unless hostname.nil?
|
103
|
+
|
104
|
+
timeout = @config.timeout || opts[:timeout] if opts.timeout?
|
105
|
+
@backup.file_item.timeout = timeout unless timeout.nil?
|
136
106
|
|
137
|
-
|
138
|
-
|
107
|
+
compression = @config.compression || opts[:compression] if opts.compression?
|
108
|
+
@backup.compression = compression unless compression.nil?
|
139
109
|
|
140
|
-
|
141
|
-
|
110
|
+
if opts.list?
|
111
|
+
jars_list = @backup.jars
|
112
|
+
|
113
|
+
unless jars_list.empty?
|
114
|
+
puts "List of jars:\n"
|
115
|
+
jars_list.keys.sort.each do |key|
|
116
|
+
puts " #{key.dark_green}: #{jars_list[key]}"
|
142
117
|
end
|
143
118
|
else
|
144
|
-
puts "
|
119
|
+
puts "Nothing to listing."
|
145
120
|
end
|
121
|
+
|
122
|
+
exit
|
146
123
|
end
|
147
124
|
|
148
|
-
|
149
|
-
|
125
|
+
if !!@config.token || opts.token?
|
126
|
+
key = @config.token || opts[:token]
|
127
|
+
puts_fail "Key #{key.dark_green} not found" unless File.exists? key
|
150
128
|
|
151
|
-
|
152
|
-
|
153
|
-
paths = opts[:rescue].split(" ")
|
154
|
-
jars_list = @backup.jars
|
129
|
+
size = (@config.size || opts[:size]).to_i
|
130
|
+
puts_fail "Unsupport #{size} bits" unless size == 4096 or size == 2048
|
155
131
|
|
156
|
-
|
132
|
+
@backup.rsa_key(key, size)
|
133
|
+
end
|
157
134
|
|
158
|
-
|
159
|
-
|
135
|
+
if opts.date?
|
136
|
+
date = opts[:date].split("-")
|
160
137
|
|
161
|
-
unless
|
162
|
-
|
163
|
-
|
138
|
+
unless date.length == 1
|
139
|
+
@start_date = Backup::Timestamp.parse_timestamp date[0]
|
140
|
+
@end_date = Backup::Timestamp.parse_timestamp date[1], true
|
164
141
|
|
165
|
-
|
142
|
+
puts_fail "Last date less than start date" if start_date > end_date
|
143
|
+
else
|
144
|
+
@start_date = Backup::Timestamp.parse_timestamp date[0]
|
145
|
+
@end_date = Backup::Timestamp.parse_timestamp date[0], true
|
146
|
+
end
|
147
|
+
else
|
148
|
+
@start_date = nil
|
149
|
+
@end_date = Time.now.utc
|
166
150
|
end
|
167
151
|
|
168
|
-
if opts.
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
152
|
+
if opts.jar?
|
153
|
+
opts[:jar].split(" ").each do |jar|
|
154
|
+
versions = @backup.jar_versions(jar)
|
155
|
+
|
156
|
+
unless versions.empty?
|
157
|
+
puts "Versions of backup '#{jar}':"
|
158
|
+
|
159
|
+
versions.each do |version|
|
160
|
+
puts " => #{version.dark_green}: #{Backup::Timestamp.to_str(version)}"
|
161
|
+
end
|
162
|
+
else
|
163
|
+
puts "Versions doesn't exists for jar: #{jar}"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
exit
|
173
168
|
end
|
174
169
|
|
175
|
-
#TODO:
|
176
|
-
|
170
|
+
#TODO: Support rescue option as hash
|
171
|
+
if opts.rescue?
|
172
|
+
paths = opts[:rescue].split(" ")
|
173
|
+
jars_list = @backup.jars
|
177
174
|
|
178
|
-
|
175
|
+
include_path = lambda {|path| jars_list.keys.include? path}
|
179
176
|
|
180
|
-
|
181
|
-
|
182
|
-
# puts "Versions: #{versions}" #FIXME
|
177
|
+
jars_hashes = paths.map do |path|
|
178
|
+
path = File.expand_path path
|
183
179
|
|
184
|
-
|
180
|
+
unless include_path[path] or include_path["#{path}/"]
|
181
|
+
puts_fail "Jar \"#{path}\" not exists."
|
182
|
+
end
|
185
183
|
|
186
|
-
|
187
|
-
|
184
|
+
jars_list[path] || jars_list["#{path}/"]
|
185
|
+
end
|
186
|
+
|
187
|
+
if opts.to?
|
188
|
+
@to = File.expand_path opts[:to]
|
189
|
+
try_create_dir @to
|
188
190
|
else
|
189
|
-
|
190
|
-
|
191
|
-
|
191
|
+
@to = "/"
|
192
|
+
end
|
193
|
+
|
194
|
+
#TODO: Confirm flag
|
195
|
+
#TODO: Empty destination directory
|
196
|
+
|
197
|
+
@index = {}
|
198
|
+
|
199
|
+
jars_hashes.each do |hash|
|
200
|
+
versions = @backup.jar_versions(hash)
|
201
|
+
# puts "Versions: #{versions}" #FIXME
|
202
|
+
|
203
|
+
last_version = Backup::Timestamp.last_from(versions, @end_date, @start_date)
|
192
204
|
|
193
|
-
unless
|
194
|
-
|
205
|
+
unless last_version.nil?
|
206
|
+
@index[hash] = last_version
|
195
207
|
else
|
196
|
-
|
208
|
+
error_path = "#{Backup::Jar.hash_to_path(@backup.file_item, @backup.root_path, hash)}"
|
209
|
+
start_date = Backup::Timestamp.to_s(@start_date)
|
210
|
+
end_date = Backup::Timestamp.to_s(@end_date)
|
211
|
+
|
212
|
+
unless @start_date.nil?
|
213
|
+
puts_fail "Nothing found for #{error_path}, between date: #{start_date} - #{end_date}"
|
214
|
+
else
|
215
|
+
puts_fail "Nothing found for #{error_path}, for date: #{end_date}"
|
216
|
+
end
|
197
217
|
end
|
198
218
|
end
|
199
|
-
end
|
200
219
|
|
201
|
-
|
202
|
-
|
203
|
-
|
220
|
+
@index.each do |hash, timestamp|
|
221
|
+
@backup.restore_jar_to(hash, timestamp, @to)
|
222
|
+
end
|
223
|
+
|
224
|
+
puts "Done!".green
|
225
|
+
exit
|
204
226
|
end
|
205
227
|
|
206
|
-
|
207
|
-
|
208
|
-
|
228
|
+
if !!@config.paths or opts.add?
|
229
|
+
if File.exists? "/var/tmp/encbs.swap"
|
230
|
+
meta = YAML::load open("/var/tmp/encbs.swap").read
|
231
|
+
jar_path, timestamp = meta[:jar_path], meta[:timestamp]
|
232
|
+
dirs = @backup.file_item.dir File.expand_path("../", jar_path)
|
233
|
+
|
234
|
+
if dirs.include? File.basename(jar_path)
|
235
|
+
meta.delete :timestamp
|
236
|
+
meta.delete :jar_path
|
237
|
+
|
238
|
+
@backup.file_item.create_file_once(
|
239
|
+
"#{jar_path}/#{timestamp}.yml",
|
240
|
+
meta.to_yaml
|
241
|
+
)
|
242
|
+
|
243
|
+
FileUtils.rm "/var/tmp/encbs.swap"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
if opts.add?
|
248
|
+
paths = opts[:add].split(" ")
|
249
|
+
else
|
250
|
+
paths = @config.paths.split(" ")
|
251
|
+
end
|
209
252
|
|
210
|
-
|
211
|
-
|
253
|
+
paths = paths.map do |path|
|
254
|
+
path = File.expand_path path
|
255
|
+
puts_fail "Path \"#{path}\" not exists." unless File.exists? path
|
212
256
|
|
213
|
-
|
214
|
-
|
215
|
-
puts_fail "Path \"#{path}\" not exists." unless File.exists? path
|
257
|
+
path
|
258
|
+
end
|
216
259
|
|
217
|
-
path
|
218
|
-
|
260
|
+
paths.each do |path|
|
261
|
+
@backup.create! path, @config.increment || opts.increment?
|
262
|
+
end
|
219
263
|
|
220
|
-
|
221
|
-
@backup.create! path, @config.increment || opts.increment?
|
264
|
+
puts "Done!".green
|
222
265
|
end
|
223
|
-
|
224
|
-
|
225
|
-
end
|
266
|
+
ensure
|
267
|
+
remove_lock
|
268
|
+
end
|
data/encbs.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{encbs}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0.alpha"
|
9
9
|
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new("
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Timothy Klim"]
|
12
|
-
s.date = %q{2011-05-
|
12
|
+
s.date = %q{2011-05-23}
|
13
13
|
s.default_executable = %q{encbs}
|
14
14
|
s.description = %q{Simple backup system for pushing into cloud}
|
15
15
|
s.email = %q{klimtimothy@gmail.com}
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
|
|
26
26
|
"VERSION",
|
27
27
|
"bin/encbs",
|
28
28
|
"encbs.gemspec",
|
29
|
+
"lib/archive.rb",
|
29
30
|
"lib/backup.rb",
|
30
31
|
"lib/backup/file_item.rb",
|
31
32
|
"lib/backup/file_item/base.rb",
|
@@ -58,6 +59,8 @@ Gem::Specification.new do |s|
|
|
58
59
|
s.add_runtime_dependency(%q<fog>, [">= 0"])
|
59
60
|
s.add_runtime_dependency(%q<slop>, [">= 0"])
|
60
61
|
s.add_runtime_dependency(%q<ruby-progressbar>, [">= 0"])
|
62
|
+
s.add_runtime_dependency(%q<lzoruby>, [">= 0"])
|
63
|
+
s.add_development_dependency(%q<rake>, ["= 0.8.4"])
|
61
64
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
62
65
|
s.add_development_dependency(%q<jeweler>, ["~> 1.6.0"])
|
63
66
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
@@ -65,6 +68,8 @@ Gem::Specification.new do |s|
|
|
65
68
|
s.add_dependency(%q<fog>, [">= 0"])
|
66
69
|
s.add_dependency(%q<slop>, [">= 0"])
|
67
70
|
s.add_dependency(%q<ruby-progressbar>, [">= 0"])
|
71
|
+
s.add_dependency(%q<lzoruby>, [">= 0"])
|
72
|
+
s.add_dependency(%q<rake>, ["= 0.8.4"])
|
68
73
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
69
74
|
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
70
75
|
s.add_dependency(%q<rcov>, [">= 0"])
|
@@ -73,6 +78,8 @@ Gem::Specification.new do |s|
|
|
73
78
|
s.add_dependency(%q<fog>, [">= 0"])
|
74
79
|
s.add_dependency(%q<slop>, [">= 0"])
|
75
80
|
s.add_dependency(%q<ruby-progressbar>, [">= 0"])
|
81
|
+
s.add_dependency(%q<lzoruby>, [">= 0"])
|
82
|
+
s.add_dependency(%q<rake>, ["= 0.8.4"])
|
76
83
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
77
84
|
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
78
85
|
s.add_dependency(%q<rcov>, [">= 0"])
|
data/lib/archive.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'zlib'
|
2
|
+
require 'lzoruby'
|
3
|
+
|
4
|
+
module GZIP
|
5
|
+
def self.compress string, level
|
6
|
+
z = Zlib::Deflate.new level
|
7
|
+
dst = z.deflate string, Zlib::FINISH
|
8
|
+
z.close
|
9
|
+
dst
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.decompress string
|
13
|
+
zstream = Zlib::Inflate.new
|
14
|
+
buf = zstream.inflate string
|
15
|
+
zstream.finish
|
16
|
+
zstream.close
|
17
|
+
buf
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Archive
|
22
|
+
attr_reader :type
|
23
|
+
|
24
|
+
def initialize type
|
25
|
+
fail "Error" unless [:lzo, :gzip].include? type.downcase
|
26
|
+
instance_eval %{@type = #{type.to_s.upcase}}
|
27
|
+
end
|
28
|
+
|
29
|
+
def method_missing name, *args
|
30
|
+
StringIO.new @type.send(name, *args)
|
31
|
+
end
|
32
|
+
end
|
@@ -9,7 +9,7 @@ module Backup
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
def stat(file
|
12
|
+
def stat(file)
|
13
13
|
files = {}
|
14
14
|
|
15
15
|
stat = File.new(file).stat
|
@@ -18,10 +18,8 @@ module Backup
|
|
18
18
|
:gid => stat.gid,
|
19
19
|
:mode => stat.mode
|
20
20
|
}
|
21
|
-
files[file][:timestamp] = timestamp if timestamp
|
22
|
-
|
23
21
|
unless Dir.exists?(file)
|
24
|
-
files[file][:checksum] = Digest::MD5.hexdigest
|
22
|
+
files[file][:checksum] = Digest::MD5.hexdigest File.open(file, 'rb').read
|
25
23
|
end
|
26
24
|
|
27
25
|
files
|
@@ -3,7 +3,7 @@ require 'backup/file_item/base'
|
|
3
3
|
module Backup
|
4
4
|
module FileItem
|
5
5
|
class Cloud < Backup::FileItem::Base
|
6
|
-
attr_reader :key, :secret, :backet, :provider
|
6
|
+
attr_reader :key, :secret, :backet, :provider, :timeout
|
7
7
|
|
8
8
|
def initialize(args = {})
|
9
9
|
puts_fail "Empty hash in Cloud initialize method" if args.empty?
|
@@ -12,12 +12,16 @@ module Backup
|
|
12
12
|
puts_fail "'#{arg.to_s.green}' should not be empty" if args[arg].nil?
|
13
13
|
instance_eval %{@#{arg} = args[:#{arg}]}
|
14
14
|
end
|
15
|
+
@timeout = 60
|
15
16
|
|
16
|
-
|
17
|
+
try_to_connect_with_cloud
|
18
|
+
end
|
19
|
+
|
20
|
+
def timeout=(time)
|
21
|
+
@timeout = time
|
17
22
|
end
|
18
23
|
|
19
24
|
def create_directory_once(*directories)
|
20
|
-
# Nothing happen
|
21
25
|
end
|
22
26
|
|
23
27
|
def create_file_once(file, data)
|
@@ -44,7 +48,7 @@ module Backup
|
|
44
48
|
files = @directory.files.all(
|
45
49
|
:prefix => path,
|
46
50
|
:max_keys => 30_000
|
47
|
-
).map
|
51
|
+
).map(&:key)
|
48
52
|
|
49
53
|
files.map do |item|
|
50
54
|
match = item.match(/^#{path}\/([^\/]+#{mask}).*$/)
|
@@ -64,6 +68,7 @@ module Backup
|
|
64
68
|
begin
|
65
69
|
yield
|
66
70
|
rescue Exception => e
|
71
|
+
sleep @timeout
|
67
72
|
try_to_connect_with_cloud
|
68
73
|
|
69
74
|
yield
|
@@ -1,8 +1,14 @@
|
|
1
1
|
require 'backup/file_item/base'
|
2
2
|
|
3
3
|
module Backup
|
4
|
-
|
4
|
+
module FileItem
|
5
5
|
class Local < Backup::FileItem::Base
|
6
|
+
attr_reader :timeout
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@timeout = 0
|
10
|
+
end
|
11
|
+
|
6
12
|
def create_directory_once(*directories)
|
7
13
|
directories.each do |path|
|
8
14
|
FileUtils.mkdir_p(path) unless Dir.exists?(path)
|
@@ -10,16 +16,24 @@ module Backup
|
|
10
16
|
end
|
11
17
|
|
12
18
|
def create_file_once(file, data)
|
13
|
-
|
14
|
-
File.open(file, "
|
19
|
+
data = data.read if data.is_a? File or data.is_a? StringIO
|
20
|
+
File.open(file, "wb").puts(data) unless File.exists?(file)
|
15
21
|
end
|
16
22
|
|
17
23
|
def read_file(file)
|
18
|
-
open(file).read if File.exists? file
|
24
|
+
File.open(file, 'rb').read if File.exists? file
|
25
|
+
end
|
26
|
+
|
27
|
+
def timeout=(time)
|
19
28
|
end
|
20
29
|
|
21
30
|
def dir(path, mask = "*")
|
22
|
-
|
31
|
+
r_mask = mask.gsub('.', '\.').gsub('*', '[^\/]')
|
32
|
+
|
33
|
+
Dir["#{path}/#{mask}"].map do |item|
|
34
|
+
match = item.match(/^#{path}\/([^\/]+#{r_mask}).*$/)
|
35
|
+
match[1] if match
|
36
|
+
end.compact.uniq
|
23
37
|
end
|
24
38
|
end
|
25
39
|
end
|
data/lib/backup/jar.rb
CHANGED
@@ -12,82 +12,112 @@ module Backup
|
|
12
12
|
Digest::MD5.hexdigest(@local_path)
|
13
13
|
end
|
14
14
|
|
15
|
-
def save
|
16
|
-
|
17
|
-
|
18
|
-
else
|
19
|
-
@local_files = {}
|
20
|
-
current_files = hash_local_files
|
15
|
+
def save increment = false, compression = nil
|
16
|
+
@meta_index = {}
|
17
|
+
@local_files = hash_local_files
|
21
18
|
|
19
|
+
if increment
|
22
20
|
last_timestamp = Jar.jar_versions(@file_item, @root_path, jar_hash, true).last
|
23
21
|
|
24
22
|
if last_timestamp.nil?
|
25
23
|
puts_fail "First you must create a full backup for #{@local_path.dark_green}"
|
26
24
|
end
|
27
25
|
|
28
|
-
last_index = Jar.fetch_index_for(@file_item, @root_path, jar_hash, last_timestamp)
|
29
|
-
|
30
|
-
current_files.keys.each do |file|
|
31
|
-
@local_files[file] = current_files[file]
|
26
|
+
@last_index = Jar.fetch_index_for(@file_item, @root_path, jar_hash, last_timestamp)
|
32
27
|
|
33
|
-
|
34
|
-
current =
|
28
|
+
@local_files.keys.each do |file|
|
29
|
+
current = @local_files[file].dup
|
35
30
|
current.delete(:timestamp)
|
36
|
-
|
37
|
-
unless last_index[file].nil?
|
38
|
-
backup = last_index[file].dup
|
31
|
+
|
32
|
+
unless @last_index[file].nil?
|
33
|
+
backup = @last_index[file].dup
|
39
34
|
backup.delete(:timestamp)
|
40
|
-
|
35
|
+
|
41
36
|
if (current == backup) or
|
42
37
|
(!current[:checksum].nil? and current[:checksum] == backup[:checksum])
|
43
|
-
|
44
|
-
@
|
38
|
+
|
39
|
+
@meta_index[file] = @local_files[file]
|
40
|
+
@meta_index[file][:timestamp] = @last_index[file][:timestamp]
|
45
41
|
end
|
46
42
|
end
|
47
|
-
# }
|
48
43
|
end
|
49
44
|
end
|
50
45
|
|
46
|
+
unless @key.nil?
|
47
|
+
@meta_index.merge!({
|
48
|
+
:checksum => Base64.encode64(@key.encrypt(@timestamp))
|
49
|
+
})
|
50
|
+
end
|
51
|
+
|
52
|
+
unless compression.nil?
|
53
|
+
@meta_index.merge!({
|
54
|
+
:compression => compression.type.to_s
|
55
|
+
})
|
56
|
+
end
|
57
|
+
|
51
58
|
@file_item.create_directory_once meta_jars_path, meta_jar_path, jar_data_path
|
52
59
|
@file_item.create_file_once(
|
53
|
-
|
60
|
+
"#{meta_jars_path}/#{jar_hash}",
|
54
61
|
@file_item.semantic_path(@local_path)
|
55
62
|
)
|
56
|
-
@file_item.create_file_once(
|
57
|
-
"#{meta_jar_path}/#{@timestamp}.yml",
|
58
|
-
@local_files.to_yaml
|
59
|
-
)
|
60
63
|
|
61
|
-
@local_files.select! {|k, v| v[:timestamp] == @timestamp}
|
62
64
|
if @file_item.is_a? Backup::FileItem::Cloud
|
63
65
|
pbar = ProgressBar.new(
|
64
|
-
|
66
|
+
"Uploading",
|
65
67
|
@local_files.keys.count
|
66
68
|
)
|
67
69
|
else
|
68
70
|
pbar = ProgressBar.new(
|
69
|
-
|
71
|
+
"Copying",
|
70
72
|
@local_files.keys.count
|
71
73
|
)
|
72
74
|
end
|
73
|
-
|
75
|
+
|
74
76
|
pbar.bar_mark = '*'
|
75
77
|
|
76
|
-
@
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
78
|
+
#@local_files = @meta_index.select {|k, v| v[:timestamp] == @timestamp if v.is_a? Hash}
|
79
|
+
|
80
|
+
begin
|
81
|
+
@local_files.keys.each do |file|
|
82
|
+
if @meta_index[file].nil?
|
83
|
+
unless Dir.exists?(file)
|
84
|
+
data = StringIO.new File.open(file, 'rb').read
|
85
|
+
checksum = Digest::MD5.hexdigest(data.read)
|
86
|
+
|
87
|
+
data.seek 0
|
88
|
+
data = compression.compress(data.read, 3) unless compression.nil?
|
89
|
+
|
90
|
+
data = @key.encrypt_to_stream(data) if @key
|
91
|
+
|
92
|
+
@file_item.create_file_once(
|
93
|
+
"#{jar_data_path}/#{@file_item.file_hash file}",
|
94
|
+
data
|
95
|
+
)
|
96
|
+
|
97
|
+
pbar.inc
|
98
|
+
end
|
99
|
+
|
100
|
+
@meta_index[file] = @local_files[file]
|
101
|
+
@meta_index[file][:checksum] = checksum
|
102
|
+
@meta_index[file][:timestamp] = @timestamp
|
82
103
|
end
|
83
|
-
|
84
|
-
@file_item.create_file_once(
|
85
|
-
"#{jar_data_path}/#{@file_item.file_hash file}",
|
86
|
-
data
|
87
|
-
)
|
88
|
-
|
89
|
-
pbar.inc
|
90
104
|
end
|
105
|
+
rescue Exception => e
|
106
|
+
@meta_index.merge!({
|
107
|
+
:jar_path => meta_jar_path,
|
108
|
+
:timestamp => @timestamp
|
109
|
+
})
|
110
|
+
File.open("/var/tmp/encbs.swap", "w") do |f|
|
111
|
+
f.puts @meta_index.to_yaml
|
112
|
+
end
|
113
|
+
|
114
|
+
puts
|
115
|
+
puts_fail "Index file has been saved that to allow upload into cloud in next run."
|
116
|
+
else
|
117
|
+
@file_item.create_file_once(
|
118
|
+
"#{meta_jar_path}/#{@timestamp}.yml",
|
119
|
+
@meta_index.to_yaml
|
120
|
+
)
|
91
121
|
end
|
92
122
|
|
93
123
|
pbar.finish
|
@@ -96,8 +126,6 @@ module Backup
|
|
96
126
|
def hash_local_files
|
97
127
|
files = {}
|
98
128
|
|
99
|
-
puts_verbose "Create index for #{@local_path.dark_green}"
|
100
|
-
|
101
129
|
if Dir.exists? @local_path
|
102
130
|
matches = Dir.glob(File.join(@local_path, "/**/*"), File::FNM_DOTMATCH)
|
103
131
|
|
@@ -108,10 +136,10 @@ module Backup
|
|
108
136
|
matches << @local_path
|
109
137
|
|
110
138
|
matches.each do |match|
|
111
|
-
files.merge!(@file_item.stat
|
139
|
+
files.merge!(@file_item.stat match)
|
112
140
|
end
|
113
141
|
else
|
114
|
-
files = @file_item.stat
|
142
|
+
files = @file_item.stat @local_path
|
115
143
|
end
|
116
144
|
|
117
145
|
files
|
data/lib/backup.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
1
3
|
require 'backup/file_item'
|
2
4
|
require 'backup/timestamp'
|
3
5
|
require 'backup/jar'
|
6
|
+
require 'archive'
|
4
7
|
require 'crypto'
|
5
8
|
|
6
9
|
module Backup
|
7
10
|
class Instance
|
8
|
-
attr_reader :root_path, :timestamp, :hostname, :file_item
|
11
|
+
attr_reader :root_path, :timestamp, :hostname, :file_item, :compression
|
9
12
|
|
10
13
|
def initialize(root_path, cloud = false, *args)
|
11
14
|
if cloud
|
@@ -15,22 +18,27 @@ module Backup
|
|
15
18
|
end
|
16
19
|
|
17
20
|
@hostname = Socket.gethostname
|
21
|
+
@_root_path = @root_path
|
18
22
|
@root_path = "#{root_path}/#{@hostname}"
|
19
23
|
@timestamp = Backup::Timestamp.create
|
20
24
|
end
|
21
25
|
|
26
|
+
def compression= type
|
27
|
+
@compression = Archive.new type.to_sym
|
28
|
+
end
|
29
|
+
|
22
30
|
def hostname=(host)
|
23
31
|
@hostname = host
|
24
|
-
@root_path = "#{
|
32
|
+
@root_path = "#{@_root_path}/#{@hostname}"
|
25
33
|
end
|
26
34
|
|
27
|
-
def
|
28
|
-
@key = Crypto::Key.from_file(path)
|
35
|
+
def rsa_key(path, size)
|
36
|
+
@key = Crypto::Key.from_file(path, size)
|
29
37
|
end
|
30
38
|
|
31
39
|
def create!(local_path, increment = false)
|
32
40
|
jar = Jar.new(@file_item, @root_path, local_path, @key)
|
33
|
-
jar.save(increment)
|
41
|
+
jar.save(increment, @compression)
|
34
42
|
end
|
35
43
|
|
36
44
|
def jars
|
@@ -44,8 +52,24 @@ module Backup
|
|
44
52
|
def restore_jar_to(hash, timestamp, to)
|
45
53
|
files = Jar.fetch_index_for(@file_item, @root_path, hash, timestamp)
|
46
54
|
|
55
|
+
unless files[:checksum].nil?
|
56
|
+
if @key.nil? or
|
57
|
+
@key.decrypt(Base64.decode64(files[:checksum])) != timestamp
|
58
|
+
|
59
|
+
puts_fail "Checksum does not match."
|
60
|
+
end
|
61
|
+
files.delete :checksum
|
62
|
+
end
|
63
|
+
|
64
|
+
unless files[:compression].nil?
|
65
|
+
compression = Archive.new files[:compression].to_sym
|
66
|
+
files.delete :compression
|
67
|
+
else
|
68
|
+
compression = nil
|
69
|
+
end
|
70
|
+
|
47
71
|
pbar = ProgressBar.new(
|
48
|
-
|
72
|
+
"Restoring",
|
49
73
|
files.keys.length
|
50
74
|
)
|
51
75
|
pbar.bar_mark = '*'
|
@@ -67,22 +91,27 @@ module Backup
|
|
67
91
|
restore_file,
|
68
92
|
file_ok[:uid],
|
69
93
|
file_ok[:gid],
|
70
|
-
|
94
|
+
current_file[:uid],
|
71
95
|
current_file[:gid]
|
72
96
|
)
|
73
97
|
else
|
74
98
|
try_create_dir(File.dirname restore_file)
|
75
99
|
|
76
100
|
begin
|
77
|
-
File.open(restore_file, "
|
101
|
+
File.open(restore_file, "wb") do |f|
|
78
102
|
f.chmod current_file[:mode]
|
79
103
|
f.chown current_file[:uid], current_file[:gid]
|
80
104
|
|
81
105
|
remote_path = "#{@root_path}/#{hash}/#{current_file[:timestamp]}"
|
82
106
|
remote_path += "/#{@file_item.file_hash file}"
|
83
107
|
|
84
|
-
data = @file_item.read_file
|
85
|
-
|
108
|
+
data = @file_item.read_file(remote_path)
|
109
|
+
data = @key.decrypt_from_stream data if @key
|
110
|
+
|
111
|
+
unless compression.nil?
|
112
|
+
data = compression.decompress(data.chomp).read
|
113
|
+
end
|
114
|
+
|
86
115
|
f.puts data
|
87
116
|
end
|
88
117
|
|
@@ -90,7 +119,7 @@ module Backup
|
|
90
119
|
|
91
120
|
check_mode(restore_file, file_ok[:mode], current_file[:mode])
|
92
121
|
check_rights(
|
93
|
-
|
122
|
+
restore_file,
|
94
123
|
file_ok[:uid],
|
95
124
|
file_ok[:gid],
|
96
125
|
current_file[:uid],
|
data/lib/crypto.rb
CHANGED
@@ -11,13 +11,14 @@ module Crypto
|
|
11
11
|
end
|
12
12
|
|
13
13
|
class Key
|
14
|
-
def initialize(data)
|
14
|
+
def initialize(data, size)
|
15
15
|
@public = (data =~ /^-----BEGIN (RSA|DSA) PRIVATE KEY-----$/).nil?
|
16
16
|
@key = OpenSSL::PKey::RSA.new(data)
|
17
|
+
@size = (size == 4096 ? 512 : 256)
|
17
18
|
end
|
18
19
|
|
19
|
-
def self.from_file(filename)
|
20
|
-
self.new
|
20
|
+
def self.from_file(filename, size = 4096)
|
21
|
+
self.new(File.read(filename), size)
|
21
22
|
end
|
22
23
|
|
23
24
|
def encrypt_to_stream(data)
|
@@ -28,15 +29,16 @@ module Crypto
|
|
28
29
|
encrypt_data << encrypt(buf)
|
29
30
|
end
|
30
31
|
|
31
|
-
encrypt_data.seek
|
32
|
+
encrypt_data.seek 0
|
32
33
|
encrypt_data
|
33
34
|
end
|
34
35
|
|
35
36
|
def decrypt_from_stream(data)
|
36
|
-
encrypt_data = StringIO.new
|
37
|
+
encrypt_data = StringIO.new(data.chomp)
|
38
|
+
encrypt_data.seek 0
|
37
39
|
decrypt_data = ""
|
38
40
|
|
39
|
-
while buf = encrypt_data.read(
|
41
|
+
while buf = encrypt_data.read(@size) do
|
40
42
|
decrypt_data += decrypt(buf)
|
41
43
|
end
|
42
44
|
|
@@ -45,10 +47,14 @@ module Crypto
|
|
45
47
|
|
46
48
|
def encrypt(text)
|
47
49
|
@key.send("#{key_type}_encrypt", text)
|
50
|
+
rescue Exception => e
|
51
|
+
puts_fail "RSA encrypt error: #{e.message}"
|
48
52
|
end
|
49
53
|
|
50
54
|
def decrypt(text)
|
51
55
|
@key.send("#{key_type}_decrypt", text)
|
56
|
+
rescue Exception => e
|
57
|
+
puts_fail "RSA decrypt error: #{e.message}"
|
52
58
|
end
|
53
59
|
|
54
60
|
def private?
|
data/lib/encbsconfig.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
class EncbsConfig
|
2
|
-
attr_reader :paths, :bucket, :colorize, :
|
3
|
-
:secret, :token, :verbose
|
2
|
+
attr_reader :paths, :bucket, :colorize, :compression, :hostname, :increment,
|
3
|
+
:key, :secret, :size, :token, :timeout, :verbose
|
4
4
|
|
5
5
|
def initialize
|
6
6
|
@paths = ""
|
7
7
|
end
|
8
8
|
|
9
9
|
def load(path)
|
10
|
-
[:bucket, :colorize, :hostname, :increment, :key, :secret,
|
11
|
-
:token, :verbose].each {|attr| eval "@#{attr} = nil"}
|
10
|
+
[:bucket, :colorize, :compression, :hostname, :increment, :key, :secret,
|
11
|
+
:size, :token, :timeout, :verbose].each {|attr| eval "@#{attr} = nil"}
|
12
12
|
|
13
13
|
@paths = ""
|
14
14
|
|
15
|
-
|
15
|
+
instance_eval "#{open(path).read}"
|
16
16
|
end
|
17
17
|
|
18
|
-
def use_hostname
|
18
|
+
def use_hostname attr
|
19
19
|
@hostname = attr
|
20
20
|
end
|
21
21
|
|
@@ -27,27 +27,39 @@ class EncbsConfig
|
|
27
27
|
@colorize = true
|
28
28
|
end
|
29
29
|
|
30
|
-
def public_key
|
30
|
+
def public_key attr
|
31
31
|
@token = attr
|
32
32
|
end
|
33
33
|
|
34
34
|
def increment!
|
35
35
|
@increment = true
|
36
36
|
end
|
37
|
+
|
38
|
+
def use_compression attr
|
39
|
+
@compression = attr
|
40
|
+
end
|
37
41
|
|
38
|
-
def aws_key
|
42
|
+
def aws_key attr
|
39
43
|
@key = attr
|
40
44
|
end
|
41
45
|
|
42
|
-
def aws_secret
|
46
|
+
def aws_secret attr
|
43
47
|
@secret = attr
|
44
48
|
end
|
45
49
|
|
46
|
-
def aws_bucket
|
50
|
+
def aws_bucket attr
|
47
51
|
@bucket = attr
|
48
52
|
end
|
49
53
|
|
54
|
+
def key_size attr
|
55
|
+
@size = attr
|
56
|
+
end
|
57
|
+
|
50
58
|
def verbose!
|
51
59
|
@verbose = true
|
52
60
|
end
|
61
|
+
|
62
|
+
def set_timeout attr
|
63
|
+
@timeout = attr
|
64
|
+
end
|
53
65
|
end
|
data/lib/helpers.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
def puts_fail(msg)
|
2
|
-
STDERR.puts "#{"Error
|
2
|
+
STDERR.puts "#{"Error! ".red}#{msg}"
|
3
3
|
|
4
4
|
exit msg.length
|
5
5
|
end
|
@@ -12,15 +12,6 @@ def print_verbose(msg)
|
|
12
12
|
print msg if $PRINT_VERBOSE
|
13
13
|
end
|
14
14
|
|
15
|
-
def safe_require(&block)
|
16
|
-
yield
|
17
|
-
rescue Exception => e
|
18
|
-
puts_fail %Q{This script use these gems: fog, slop.
|
19
|
-
Make sure that you have them all.
|
20
|
-
If you don't have, you may install them: $ gem install fog slop ruby-progressbar
|
21
|
-
}
|
22
|
-
end
|
23
|
-
|
24
15
|
def try_create_dir(dir)
|
25
16
|
begin
|
26
17
|
FileUtils.mkdir_p dir unless Dir.exists? dir
|
@@ -41,6 +32,20 @@ def check_rights(file, first_uid, first_gid, second_uid, second_gid)
|
|
41
32
|
end
|
42
33
|
end
|
43
34
|
|
35
|
+
def create_lock
|
36
|
+
open("/tmp/encbs.lock", "w") do |f|
|
37
|
+
f.puts Process.pid
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def remove_lock
|
42
|
+
FileUtils.rm "/tmp/encbs.lock" if File.exists? "/tmp/encbs.lock"
|
43
|
+
end
|
44
|
+
|
45
|
+
def lock_exists?
|
46
|
+
File.exists? "/tmp/encbs.lock"
|
47
|
+
end
|
48
|
+
|
44
49
|
class String
|
45
50
|
def red
|
46
51
|
colorize(self, "\e[1m\e[31m")
|
data/test/helper.rb
CHANGED
@@ -12,30 +12,22 @@ class BackupFileItemTest < Test::Unit::TestCase
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_file_stat
|
15
|
-
file = @file_item.stat
|
16
|
-
__FILE__,
|
17
|
-
Backup::Timestamp.create
|
18
|
-
)
|
15
|
+
file = @file_item.stat __FILE__
|
19
16
|
key = file.keys.first
|
20
17
|
|
21
18
|
assert_not_nil file[key][:uid]
|
22
19
|
assert_not_nil file[key][:gid]
|
23
20
|
assert_not_nil file[key][:mode]
|
24
21
|
assert_not_nil file[key][:checksum]
|
25
|
-
assert_not_nil file[key][:timestamp]
|
26
22
|
end
|
27
23
|
|
28
24
|
def test_directory_stat
|
29
|
-
file = @file_item.stat(
|
30
|
-
File.dirname(__FILE__),
|
31
|
-
Backup::Timestamp.create
|
32
|
-
)
|
25
|
+
file = @file_item.stat File.dirname(__FILE__)
|
33
26
|
key = file.keys.first
|
34
27
|
|
35
28
|
assert_not_nil file[key][:uid]
|
36
29
|
assert_not_nil file[key][:gid]
|
37
30
|
assert_not_nil file[key][:mode]
|
38
31
|
assert_nil file[key][:checksum]
|
39
|
-
assert_not_nil file[key][:timestamp]
|
40
32
|
end
|
41
33
|
end
|
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: encbs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
version: 0.
|
4
|
+
prerelease: 6
|
5
|
+
version: 0.2.0.alpha
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Timothy Klim
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-05-
|
13
|
+
date: 2011-05-23 00:00:00 +04:00
|
14
14
|
default_executable: encbs
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -47,8 +47,30 @@ dependencies:
|
|
47
47
|
prerelease: false
|
48
48
|
version_requirements: *id003
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
|
-
name:
|
50
|
+
name: lzoruby
|
51
51
|
requirement: &id004 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: rake
|
62
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - "="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.8.4
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: *id005
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: bundler
|
73
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
52
74
|
none: false
|
53
75
|
requirements:
|
54
76
|
- - ~>
|
@@ -56,10 +78,10 @@ dependencies:
|
|
56
78
|
version: 1.0.0
|
57
79
|
type: :development
|
58
80
|
prerelease: false
|
59
|
-
version_requirements: *
|
81
|
+
version_requirements: *id006
|
60
82
|
- !ruby/object:Gem::Dependency
|
61
83
|
name: jeweler
|
62
|
-
requirement: &
|
84
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
63
85
|
none: false
|
64
86
|
requirements:
|
65
87
|
- - ~>
|
@@ -67,10 +89,10 @@ dependencies:
|
|
67
89
|
version: 1.6.0
|
68
90
|
type: :development
|
69
91
|
prerelease: false
|
70
|
-
version_requirements: *
|
92
|
+
version_requirements: *id007
|
71
93
|
- !ruby/object:Gem::Dependency
|
72
94
|
name: rcov
|
73
|
-
requirement: &
|
95
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
74
96
|
none: false
|
75
97
|
requirements:
|
76
98
|
- - ">="
|
@@ -78,7 +100,7 @@ dependencies:
|
|
78
100
|
version: "0"
|
79
101
|
type: :development
|
80
102
|
prerelease: false
|
81
|
-
version_requirements: *
|
103
|
+
version_requirements: *id008
|
82
104
|
description: Simple backup system for pushing into cloud
|
83
105
|
email: klimtimothy@gmail.com
|
84
106
|
executables:
|
@@ -96,6 +118,7 @@ files:
|
|
96
118
|
- VERSION
|
97
119
|
- bin/encbs
|
98
120
|
- encbs.gemspec
|
121
|
+
- lib/archive.rb
|
99
122
|
- lib/backup.rb
|
100
123
|
- lib/backup/file_item.rb
|
101
124
|
- lib/backup/file_item/base.rb
|
@@ -128,16 +151,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
128
151
|
requirements:
|
129
152
|
- - ">="
|
130
153
|
- !ruby/object:Gem::Version
|
131
|
-
hash: -
|
154
|
+
hash: -2056087500533480585
|
132
155
|
segments:
|
133
156
|
- 0
|
134
157
|
version: "0"
|
135
158
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
159
|
none: false
|
137
160
|
requirements:
|
138
|
-
- - "
|
161
|
+
- - ">"
|
139
162
|
- !ruby/object:Gem::Version
|
140
|
-
version:
|
163
|
+
version: 1.3.1
|
141
164
|
requirements: []
|
142
165
|
|
143
166
|
rubyforge_project:
|