filbunke 2.0.9 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/Gemfile +5 -1
- data/Rakefile +22 -7
- data/VERSION +1 -1
- data/filbunke.gemspec +10 -10
- data/lib/filbunke/client.rb +89 -73
- data/lib/filbunke/daemon.rb +1 -0
- data/lib/filbunke/repository.rb +3 -1
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bdf27520bab96738e5a12465ccd526ee4d3d837a
|
4
|
+
data.tar.gz: dbb247721d46a2b8aafe2d5942120850b304fd3a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6754b1ac1376a1f491d7159fe09ab95b474637b144d2ab09fdbea87fd724234e2cf9ee5d535a6678cfbcca585dd681f186df7c193cceb6e0480d3f154536825c
|
7
|
+
data.tar.gz: 17084f8cc91464c6a9a2d1a47f5b2df0c732bc338bbd877f2795af9e16d44c80c1aea2d0d38304adee1bd5e8c06dce0d8503518f720da45253e4dea1123c3ee9
|
data/.gitignore
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
Gemfile.lock
|
1
|
+
Gemfile.lock
|
2
|
+
pkg/
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -3,6 +3,13 @@ require 'rake'
|
|
3
3
|
|
4
4
|
begin
|
5
5
|
require 'jeweler'
|
6
|
+
required_dependencies = {
|
7
|
+
"json" => "1.8.3",
|
8
|
+
"typhoeus" => "1.0.1",
|
9
|
+
"open4" => "1.3.4",
|
10
|
+
"mime-types" => "2.6.2",
|
11
|
+
"parallel" => "1.6.1"
|
12
|
+
}
|
6
13
|
Jeweler::Tasks.new do |gem|
|
7
14
|
gem.name = "filbunke"
|
8
15
|
gem.summary = %Q{Filbunke client}
|
@@ -10,29 +17,33 @@ begin
|
|
10
17
|
gem.email = "technical@deltaprojects.com"
|
11
18
|
gem.homepage = "https://rubygems.org/gems/filbunke"
|
12
19
|
gem.authors = ["Wouter de Bie", "Bjorn Sperber", "Karl Ravn", "Magnus Spangdal"]
|
13
|
-
gem.add_development_dependency "
|
20
|
+
gem.add_development_dependency "shoulda", "~> 0"
|
14
21
|
gem.files.exclude 'pkg'
|
15
22
|
gem.executables = ['filbunked']
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
gem.add_dependency 'mime-types', '= 2.6.2'
|
20
|
-
gem.add_dependency 'parallel', '= 1.6.1'
|
23
|
+
required_dependencies.each do |name, version|
|
24
|
+
gem.add_dependency "#{name}", "= #{version}"
|
25
|
+
end
|
21
26
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
22
27
|
end
|
23
28
|
Jeweler::GemcutterTasks.new
|
24
29
|
rescue LoadError => e
|
25
|
-
puts "Jeweler (or a dependency) not available. Install it with:
|
30
|
+
puts "Jeweler (or a dependency) not available. Install it with: \n\tgem install jeweler \nadditional dependencies;"
|
31
|
+
required_dependencies.each do |name,version|
|
32
|
+
puts "\tgem install #{name} -v #{version}"
|
33
|
+
end
|
26
34
|
raise e
|
27
35
|
end
|
28
36
|
|
37
|
+
|
29
38
|
require 'rake/testtask'
|
30
39
|
Rake::TestTask.new(:test) do |test|
|
31
40
|
test.libs << 'lib' << 'test'
|
32
41
|
test.pattern = 'test/**/test_*.rb'
|
33
42
|
test.verbose = true
|
43
|
+
test.warning = true
|
34
44
|
end
|
35
45
|
|
46
|
+
|
36
47
|
begin
|
37
48
|
require 'rcov/rcovtask'
|
38
49
|
Rcov::RcovTask.new do |test|
|
@@ -46,6 +57,10 @@ rescue LoadError
|
|
46
57
|
end
|
47
58
|
end
|
48
59
|
|
60
|
+
task :check_dependencies do
|
61
|
+
|
62
|
+
end
|
63
|
+
|
49
64
|
task :test => :check_dependencies
|
50
65
|
|
51
66
|
task :default => :test
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.0
|
1
|
+
2.1.0
|
data/filbunke.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: filbunke 2.0
|
5
|
+
# stub: filbunke 2.1.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "filbunke"
|
9
|
-
s.version = "2.0
|
9
|
+
s.version = "2.1.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Wouter de Bie", "Bjorn Sperber", "Karl Ravn", "Magnus Spangdal"]
|
14
|
-
s.date = "
|
14
|
+
s.date = "2016-03-05"
|
15
15
|
s.description = "Filbunke client and library"
|
16
16
|
s.email = "technical@deltaprojects.com"
|
17
17
|
s.executables = ["filbunked"]
|
@@ -42,31 +42,31 @@ Gem::Specification.new do |s|
|
|
42
42
|
"test/test_filbunke.rb"
|
43
43
|
]
|
44
44
|
s.homepage = "https://rubygems.org/gems/filbunke"
|
45
|
-
s.rubygems_version = "2.5.
|
45
|
+
s.rubygems_version = "2.4.5.1"
|
46
46
|
s.summary = "Filbunke client"
|
47
47
|
|
48
48
|
if s.respond_to? :specification_version then
|
49
49
|
s.specification_version = 4
|
50
50
|
|
51
51
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
52
|
-
s.add_development_dependency(%q<
|
52
|
+
s.add_development_dependency(%q<shoulda>, ["~> 0"])
|
53
53
|
s.add_runtime_dependency(%q<json>, ["= 1.8.3"])
|
54
|
-
s.add_runtime_dependency(%q<typhoeus>, ["= 0.
|
54
|
+
s.add_runtime_dependency(%q<typhoeus>, ["= 1.0.1"])
|
55
55
|
s.add_runtime_dependency(%q<open4>, ["= 1.3.4"])
|
56
56
|
s.add_runtime_dependency(%q<mime-types>, ["= 2.6.2"])
|
57
57
|
s.add_runtime_dependency(%q<parallel>, ["= 1.6.1"])
|
58
58
|
else
|
59
|
-
s.add_dependency(%q<
|
59
|
+
s.add_dependency(%q<shoulda>, ["~> 0"])
|
60
60
|
s.add_dependency(%q<json>, ["= 1.8.3"])
|
61
|
-
s.add_dependency(%q<typhoeus>, ["= 0.
|
61
|
+
s.add_dependency(%q<typhoeus>, ["= 1.0.1"])
|
62
62
|
s.add_dependency(%q<open4>, ["= 1.3.4"])
|
63
63
|
s.add_dependency(%q<mime-types>, ["= 2.6.2"])
|
64
64
|
s.add_dependency(%q<parallel>, ["= 1.6.1"])
|
65
65
|
end
|
66
66
|
else
|
67
|
-
s.add_dependency(%q<
|
67
|
+
s.add_dependency(%q<shoulda>, ["~> 0"])
|
68
68
|
s.add_dependency(%q<json>, ["= 1.8.3"])
|
69
|
-
s.add_dependency(%q<typhoeus>, ["= 0.
|
69
|
+
s.add_dependency(%q<typhoeus>, ["= 1.0.1"])
|
70
70
|
s.add_dependency(%q<open4>, ["= 1.3.4"])
|
71
71
|
s.add_dependency(%q<mime-types>, ["= 2.6.2"])
|
72
72
|
s.add_dependency(%q<parallel>, ["= 1.6.1"])
|
data/lib/filbunke/client.rb
CHANGED
@@ -10,7 +10,6 @@ module Filbunke
|
|
10
10
|
URL_KEY = 'url'
|
11
11
|
FROM_CHECKPOINT_KEY = 'from_checkpoint'
|
12
12
|
HASH_KEY = 'hash'
|
13
|
-
URI_UNSAFE_CHARACTERS = '/[^.:\/\w-]/'
|
14
13
|
|
15
14
|
|
16
15
|
def initialize(repository, logger, callbacks = [], failed_request_log_file_name = nil)
|
@@ -26,18 +25,17 @@ module Filbunke
|
|
26
25
|
def with_updated_files(last_checkpoint)
|
27
26
|
updates = get_updated_file_list(last_checkpoint)
|
28
27
|
updated_files = updates["files"] || []
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@logger.info "Updating repository: #{@repository.name}: #{updated_files.size} files. Checkpoint: #{last_checkpoint} ==> #{new_checkpoint}"
|
28
|
+
new_checkpoint = updates["checkpoint"] || 0
|
29
|
+
if updated_files.empty?
|
30
|
+
return new_checkpoint
|
31
|
+
end
|
32
|
+
@logger.info "Updating repository: #{@repository.name}: #{updated_files.size} files. Checkpoint: #{last_checkpoint} ==> #{new_checkpoint}"
|
34
33
|
|
35
34
|
@async_requests = []
|
36
|
-
|
37
35
|
callbacks_on_update = []
|
38
36
|
callbacks_on_no_change = []
|
39
37
|
callbacks_on_delete = []
|
40
|
-
|
38
|
+
has_update_file_failure = false
|
41
39
|
updated_files.each do |raw_file|
|
42
40
|
file = File.new(raw_file)
|
43
41
|
local_file_path = ::File.join(@repository.local_path, file.path)
|
@@ -50,42 +48,57 @@ module Filbunke
|
|
50
48
|
yield file
|
51
49
|
callbacks_on_update << OpenStruct.new({ :file => file, :local_file_path => local_file_path })
|
52
50
|
else
|
53
|
-
@logger.error "Unable to
|
54
|
-
|
51
|
+
@logger.error "Unable to fetch file #{file.url} ==> #{file.path}!"
|
52
|
+
has_update_file_failure = true
|
53
|
+
break;
|
55
54
|
end
|
56
|
-
|
55
|
+
|
57
56
|
else
|
58
57
|
@logger.debug "File exists with correct hash: #{local_file_path}"
|
59
58
|
callbacks_on_no_change << OpenStruct.new({:file => file, :local_file_path => local_file_path})
|
60
59
|
end
|
61
60
|
end
|
62
61
|
end
|
63
|
-
@hydra.run
|
64
62
|
|
65
|
-
|
66
|
-
@logger.
|
67
|
-
|
63
|
+
if has_update_file_failure
|
64
|
+
@logger.error "FAILED to fetch files for #{@repository.name} last_checkpoint = #{last_checkpoint}"
|
65
|
+
return last_checkpoint
|
68
66
|
end
|
67
|
+
@logger.info "Done setting up async requests for #{@repository.name}, starting fetch..."
|
69
68
|
|
70
|
-
|
71
|
-
@
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
run_callbacks_no_change(callbacks_on_no_change)
|
76
|
-
|
77
|
-
new_checkpoint || last_checkpoint
|
78
|
-
rescue RuntimeError, SystemCallError, StandardError => e
|
79
|
-
msg = ["Callbacks failed to run; #{e.class} - #{e.message}", *e.backtrace].join("\n\t")
|
80
|
-
@logger.error "FAILED to update files for #{@repository.name} last_checkpoint = #{last_checkpoint}; #{msg}"
|
81
|
-
last_checkpoint
|
69
|
+
has_fetch_files_failure = begin
|
70
|
+
@hydra.run
|
71
|
+
@async_requests.any? do |request|
|
72
|
+
@logger.warn "request did not handle response: #{request.inspect}" if request.response.nil? || request.response.code != 200
|
73
|
+
request.response.nil? || request.response.code != 200
|
82
74
|
end
|
83
|
-
|
75
|
+
rescue RuntimeError, SystemCallError, StandardError => e
|
76
|
+
msg = ["#{e.class} - #{e.message}", *e.backtrace].join("\n\t")
|
77
|
+
@logger.error "FAILED to fetch files for #{@repository.name} last_checkpoint = #{last_checkpoint}; #{msg}"
|
78
|
+
true
|
79
|
+
end
|
80
|
+
|
81
|
+
if has_fetch_files_failure
|
84
82
|
@logger.error "FAILED to update files for #{@repository.name} last_checkpoint = #{last_checkpoint}"
|
83
|
+
return last_checkpoint
|
84
|
+
end
|
85
|
+
|
86
|
+
@logger.info "Done fetching files for #{@repository.name}, processing callbacks..."
|
87
|
+
new_or_last_checkpoint = begin
|
88
|
+
run_callbacks_delete(callbacks_on_delete)
|
89
|
+
run_callbacks(callbacks_on_update)
|
90
|
+
run_callbacks_no_change(callbacks_on_no_change)
|
91
|
+
|
92
|
+
new_checkpoint || last_checkpoint
|
93
|
+
rescue RuntimeError, SystemCallError, StandardError => e
|
94
|
+
msg = ["#{e.class} - #{e.message}", *e.backtrace].join("\n\t")
|
95
|
+
@logger.error "FAILED to process callbacks for #{@repository.name} last_checkpoint = #{last_checkpoint}; #{msg}"
|
85
96
|
last_checkpoint
|
86
97
|
end
|
98
|
+
|
99
|
+
new_or_last_checkpoint
|
87
100
|
end
|
88
|
-
|
101
|
+
|
89
102
|
def update_files!(last_checkpoint)
|
90
103
|
with_updated_files(last_checkpoint) {}
|
91
104
|
end
|
@@ -138,7 +151,7 @@ module Filbunke
|
|
138
151
|
end
|
139
152
|
|
140
153
|
def last_checkpoint
|
141
|
-
|
154
|
+
last_checkpoint_http = Net::HTTP.new(@repository.host, @repository.port)
|
142
155
|
last_checkpoint_http.start do |http|
|
143
156
|
last_checkpoint_path = "/#{UPDATES_ACTION}/#{@repository.name}/#{LAST_CHECKPOINT_ACTION}"
|
144
157
|
request = Net::HTTP::Get.new(last_checkpoint_path)
|
@@ -149,7 +162,7 @@ module Filbunke
|
|
149
162
|
return response.body.chomp.to_i
|
150
163
|
end
|
151
164
|
end
|
152
|
-
|
165
|
+
|
153
166
|
private
|
154
167
|
|
155
168
|
def log_failed_request(failed_request_command, e)
|
@@ -161,7 +174,7 @@ module Filbunke
|
|
161
174
|
end
|
162
175
|
|
163
176
|
def update_file!(file, local_file_path)
|
164
|
-
|
177
|
+
|
165
178
|
if file.url =~ /^http:\/\//
|
166
179
|
update_http_file!(file, local_file_path)
|
167
180
|
elsif (file.url =~ /^hdfs:\/\//)
|
@@ -204,6 +217,7 @@ module Filbunke
|
|
204
217
|
updates_http.read_timeout = 300 # default is 60 seconds
|
205
218
|
updates_http.start do |http|
|
206
219
|
updates_path = "/#{UPDATES_ACTION}/#{@repository.name}?#{FROM_CHECKPOINT_KEY}=#{last_checkpoint}"
|
220
|
+
updates_path = "#{updates_path}&batch_size=#{@repository.batch_size}" if @repository.batch_size > 0
|
207
221
|
begin
|
208
222
|
@logger.info "Fetching updated file list from #{updates_path}"
|
209
223
|
request = Net::HTTP::Get.new(updates_path)
|
@@ -228,38 +242,59 @@ module Filbunke
|
|
228
242
|
def update_http_file!(file, local_file_path)
|
229
243
|
begin
|
230
244
|
async_request = if @repository.user
|
231
|
-
Typhoeus::Request.new(
|
245
|
+
Typhoeus::Request.new(
|
246
|
+
URI.escape(file.url),
|
247
|
+
:followlocation => true,
|
248
|
+
:username => @repository.user,
|
249
|
+
:password => @repository.pass
|
250
|
+
)
|
232
251
|
else
|
233
|
-
Typhoeus::Request.new(
|
252
|
+
Typhoeus::Request.new(
|
253
|
+
URI.escape(file.url),
|
254
|
+
:followlocation => true
|
255
|
+
)
|
256
|
+
end
|
257
|
+
|
258
|
+
downloaded_file = nil
|
259
|
+
async_request.on_headers do |response|
|
260
|
+
if response.code != 200
|
261
|
+
raise "Downloading file #{response.effective_url} failed with status code #{response.code} --- #{response.inspect}"
|
262
|
+
end
|
263
|
+
::FileUtils.mkdir_p(::File.dirname(local_file_path))
|
264
|
+
downloaded_file = ::File.new("#{local_file_path}.tmp", "wb")
|
265
|
+
@logger.debug("Updating file #{local_file_path}")
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
async_request.on_body do |chunk, response|
|
270
|
+
downloaded_file.write(chunk) if response.code == 200
|
234
271
|
end
|
272
|
+
|
235
273
|
async_request.on_complete do |response|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
write_file!(local_file_path, response.body)
|
274
|
+
unless downloaded_file.nil?
|
275
|
+
downloaded_file.close unless downloaded_file.closed?
|
276
|
+
if response.code == 200
|
277
|
+
::FileUtils.mv "#{local_file_path}.tmp", local_file_path
|
241
278
|
else
|
242
|
-
|
243
|
-
@logger.warn "Failed to update file #{file.url}, got status code = #{response.code}#{body_if_error}"
|
279
|
+
::FileUtils.rm "#{local_file_path}.tmp" if ::File.exist? "#{local_file_path}.tmp"
|
244
280
|
end
|
245
|
-
rescue SystemCallError, StandardError => e
|
246
|
-
msg = ["#{e.class} - #{e.message}", *e.backtrace].join("\n\t")
|
247
|
-
@logger.error "Failed to update file #{file.url}: #{msg}"
|
248
281
|
end
|
249
|
-
|
250
|
-
success
|
282
|
+
true
|
251
283
|
end
|
252
284
|
@hydra.queue async_request
|
253
285
|
@async_requests << async_request
|
254
|
-
|
286
|
+
true
|
287
|
+
rescue RuntimeError, SystemCallError, StandardError => e
|
255
288
|
msg = ["#{e.class} - #{e.message}", *e.backtrace].join("\n\t")
|
256
289
|
@logger.error "Failed to update file #{file.url}: #{msg}"
|
257
|
-
|
290
|
+
unless downloaded_file.nil?
|
291
|
+
downloaded_file.close unless downloaded_file.closed?
|
292
|
+
::FileUtils.rm "#{local_file_path}.tmp" if ::File.exist? "#{local_file_path}.tmp"
|
293
|
+
end
|
294
|
+
false
|
258
295
|
end
|
259
|
-
|
260
|
-
return true
|
261
296
|
end
|
262
|
-
|
297
|
+
|
263
298
|
def update_hdfs_file!(file, local_file_path)
|
264
299
|
begin
|
265
300
|
::FileUtils.mkdir_p(::File.dirname(local_file_path))
|
@@ -268,10 +303,10 @@ module Filbunke
|
|
268
303
|
url.gsub!(/hdfs:\/\/([^\/]*)(.*)/, "hdfs://\\2")
|
269
304
|
hdfs_cmd = "#{@repository.hadoop_binary} dfs -copyToLocal #{url} #{local_file_path}.tmp"
|
270
305
|
#@logger.debug "Trying to update #{local_file_path} with '#{hdfs_cmd}'"
|
271
|
-
|
306
|
+
|
272
307
|
pid, stdin, stdout, stderr = Open4::popen4 hdfs_cmd
|
273
308
|
ignored, status = Process::waitpid2 pid
|
274
|
-
|
309
|
+
|
275
310
|
if status.exitstatus == 0 then
|
276
311
|
begin
|
277
312
|
::FileUtils.mv "#{local_file_path}.tmp", local_file_path
|
@@ -280,7 +315,7 @@ module Filbunke
|
|
280
315
|
msg = ["#{e.class} - #{e.message}", *e.backtrace].join("\n\t")
|
281
316
|
@logger.error "Failed to move hdfs file #{file.url}: #{msg}"
|
282
317
|
return false
|
283
|
-
end
|
318
|
+
end
|
284
319
|
else
|
285
320
|
@logger.error "Failed to update hdfs file #{file.url}! Unable to execute #{hdfs_cmd}"
|
286
321
|
return false
|
@@ -292,30 +327,11 @@ module Filbunke
|
|
292
327
|
end
|
293
328
|
end
|
294
329
|
|
295
|
-
def write_file!(file_path, contents)
|
296
|
-
::FileUtils.mkdir_p(::File.dirname(file_path))
|
297
|
-
@logger.debug("Updating: #{file_path}")
|
298
|
-
begin
|
299
|
-
::File.open("#{file_path}.tmp", 'w') do |file|
|
300
|
-
file.write(contents)
|
301
|
-
file.close
|
302
|
-
end
|
303
|
-
::FileUtils.mv "#{file_path}.tmp", file_path
|
304
|
-
return true
|
305
|
-
rescue StandardError => e
|
306
|
-
msg = ["#{e.class} - #{e.message}", *e.backtrace].join("\n\t")
|
307
|
-
@logger.error "Failed to move file #{file_path}: #{msg}"
|
308
|
-
return false
|
309
|
-
end
|
310
|
-
end
|
311
|
-
|
312
330
|
def delete_file!(file_path)
|
313
331
|
if ::File.exists?(file_path) then
|
314
332
|
@logger.debug("Deleting: #{file_path}")
|
315
333
|
::File.delete(file_path)
|
316
334
|
end
|
317
335
|
end
|
318
|
-
|
319
336
|
end
|
320
337
|
end
|
321
|
-
|
data/lib/filbunke/daemon.rb
CHANGED
@@ -15,6 +15,7 @@ module Filbunke
|
|
15
15
|
@logger.log("Initializing repository: #{repository_name}")
|
16
16
|
@clients << begin
|
17
17
|
repository_config["run_every"] = repository_config.fetch("run_every", @config.fetch("run_every", 10))
|
18
|
+
repository_config["batch_size"] = repository_config.fetch("batch_size", @config.fetch("batch_size", 0))
|
18
19
|
repository = Repository.new(repository_config)
|
19
20
|
callbacks = []
|
20
21
|
repository_config["callbacks"].each do |callback_name, callback_config|
|
data/lib/filbunke/repository.rb
CHANGED
@@ -11,7 +11,8 @@ module Filbunke
|
|
11
11
|
:pass,
|
12
12
|
:hadoop_binary,
|
13
13
|
:run_every,
|
14
|
-
:hydra_concurrency
|
14
|
+
:hydra_concurrency,
|
15
|
+
:batch_size
|
15
16
|
|
16
17
|
def initialize(repository_config)
|
17
18
|
@name = repository_config["filbunke_server_repository"]
|
@@ -25,6 +26,7 @@ module Filbunke
|
|
25
26
|
@hadoop_binary = repository_config["hadoop_binary"]
|
26
27
|
@run_every = repository_config.fetch("run_every", 10).to_i
|
27
28
|
@hydra_concurrency = repository_config.fetch("hydra_concurrency", 100).to_i
|
29
|
+
@batch_size = repository_config.fetch("batch_size", 0).to_i
|
28
30
|
end
|
29
31
|
|
30
32
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: filbunke
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wouter de Bie
|
@@ -11,20 +11,20 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2016-03-05 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
|
-
name:
|
17
|
+
name: shoulda
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
19
19
|
requirements:
|
20
|
-
- - "
|
20
|
+
- - "~>"
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '0'
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- - "
|
27
|
+
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
30
|
- !ruby/object:Gem::Dependency
|
@@ -47,14 +47,14 @@ dependencies:
|
|
47
47
|
requirements:
|
48
48
|
- - '='
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version: 0.
|
50
|
+
version: 1.0.1
|
51
51
|
type: :runtime
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
55
|
- - '='
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version: 0.
|
57
|
+
version: 1.0.1
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: open4
|
60
60
|
requirement: !ruby/object:Gem::Requirement
|
@@ -147,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
147
|
version: '0'
|
148
148
|
requirements: []
|
149
149
|
rubyforge_project:
|
150
|
-
rubygems_version: 2.5.
|
150
|
+
rubygems_version: 2.4.5.1
|
151
151
|
signing_key:
|
152
152
|
specification_version: 4
|
153
153
|
summary: Filbunke client
|