hobo-inviqa 0.0.8 → 0.0.9.pre.alpha

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,216 +0,0 @@
1
- require 'aws-sdk'
2
- require 'fileutils'
3
-
4
- module Hobo
5
- module Lib
6
- class S3Sync
7
- include Hobo::Logging
8
-
9
- def initialize key_id, secret
10
- opts = {
11
- :access_key_id => key_id,
12
- :secret_access_key => secret,
13
- :verify_response_body_content_length => false,
14
- :max_retries => 15
15
- }
16
-
17
- logger.debug("s3sync: Options #{opts}")
18
-
19
- @s3 = AWS::S3.new opts
20
- end
21
-
22
- def sync source, dest, opts = {}
23
- opts = { :progress => Hobo.method(:progress) }.merge(opts)
24
-
25
- source_io = io_handler(source)
26
- destination_io = io_handler(dest)
27
-
28
- logger.debug("s3sync: Synchronzing (#{source_io.class.name} -> #{destination_io.class.name}")
29
-
30
- raise "S3 -> S3 synchronisation not supported" if source_io.is_a? Remote and destination_io.is_a? Remote
31
-
32
- source_listing = source_io.ls
33
- destination_listing = destination_io.ls
34
- logger.debug("s3sync: Source listing - #{source_listing}")
35
- logger.debug("s3sync: Destination listing - #{destination_listing}")
36
-
37
- delta = delta(source_listing, destination_listing)
38
- logger.debug("s3sync: Delta #{delta}")
39
-
40
- delta[:add].each do |file|
41
- logger.debug("s3sync: Synchronizing #{file}")
42
- source_file = source_io.open(file, "r")
43
- destination_file = destination_io.open(file, "wb+")
44
-
45
- source_file.buffer
46
-
47
- size = source_file.size
48
- destination_file.write({ :size => source_file.size }) do |buffer, bytes|
49
- chunk = source_file.read(bytes)
50
- buffer.write(chunk)
51
- opts[:progress].call(file, chunk.length, size, :update)
52
- end
53
-
54
- destination_file.close
55
- source_file.close
56
-
57
- opts[:progress].call(file, 0, size, :finish)
58
- end
59
-
60
- delta[:remove].each do |file|
61
- logger.debug("s3sync: Removing #{file}")
62
- destination_io.rm(file)
63
- end
64
-
65
- return delta
66
- end
67
-
68
- private
69
-
70
- def delta source, dest
71
- to_add = (source.sort - dest.sort).map(&:first)
72
- to_remove = (dest.sort - source.sort).map(&:first)
73
- to_remove = to_remove - to_add
74
-
75
- {
76
- :add => to_add,
77
- :remove => to_remove
78
- }
79
- end
80
-
81
- def io_handler uri
82
- parsed = URI.parse(uri)
83
- parsed.scheme == 's3' ?
84
- Remote.new(@s3, parsed.host, parsed.path) :
85
- Local.new(uri)
86
- end
87
-
88
- class Local
89
- include Hobo::Logging
90
-
91
- def initialize path
92
- @path = path
93
- end
94
-
95
- def ls
96
- logger.debug("s3sync: Listing local directory: #{@path}")
97
- out = {}
98
- dir = "#{@path.chomp('/')}/"
99
- files = Dir.glob("#{dir}**/*")
100
- files.each do |file|
101
- out[file.gsub(/^#{dir}/, '')] = Digest::MD5.file(file).hexdigest
102
- end
103
- return out
104
- end
105
-
106
- def open file, mode
107
- file_path = File.join(@path, file)
108
- FileUtils.mkdir_p File.dirname(file_path)
109
- LocalFile.new File.open(file_path, mode)
110
- end
111
-
112
- def rm file
113
- File.unlink File.join(@path, file)
114
- end
115
- end
116
-
117
- class Remote
118
- include Hobo::Logging
119
-
120
- def initialize s3, bucket, prefix
121
- @s3 = s3
122
- @bucket = bucket
123
- @prefix = prefix ? "#{prefix.gsub(/^\//, '').chomp('/')}/" : ""
124
- end
125
-
126
- def ls
127
- out = {}
128
- logger.debug("s3sync: Listing remote bucket: #{@bucket} w/ prefix #{@prefix}")
129
- @s3.buckets[@bucket].objects.with_prefix(@prefix).each do |file|
130
- filename = file.key.gsub(/^#{@prefix}/, '')
131
- next if filename == ""
132
- out[filename] = file.etag.gsub('"', '')
133
- end
134
- return out
135
- end
136
-
137
- def open file, mode
138
- s3_key = File.join(@prefix, file)
139
- RemoteFile.new @s3.buckets[@bucket].objects[s3_key], @prefix
140
- end
141
-
142
- def rm file
143
- s3_key = File.join(@prefix, file)
144
- @s3.buckets[@bucket].objects[s3_key].delete
145
- end
146
- end
147
-
148
- class LocalFile
149
- def initialize file
150
- @file = file
151
- end
152
-
153
- def buffer
154
- # NOP
155
- end
156
-
157
- def read bytes
158
- @file.read bytes
159
- end
160
-
161
- def write opts = {}
162
- opts = { :chunk_size => 4096 }.merge(opts)
163
- while @file.size < opts[:size] do
164
- yield @file, opts[:chunk_size]
165
- end
166
- end
167
-
168
- def size
169
- @file.size
170
- end
171
-
172
- def close
173
- @file.close
174
- end
175
- end
176
-
177
- class RemoteFile
178
- def initialize object, prefix
179
- @object = object
180
- @prefix = prefix
181
- @r_buffer, @w_buffer = IO.pipe
182
- @buffer_thread = nil
183
- end
184
-
185
- def buffer
186
- @buffer_thread = Thread.new do
187
- @object.read do |chunk|
188
- @w_buffer.write chunk
189
- end
190
- end
191
- end
192
-
193
- def read bytes
194
- @r_buffer.readpartial(bytes)
195
- end
196
-
197
- def write opts = {}
198
- s3_opts = { :single_request => true, :content_length => opts[:size] }
199
- @object.write s3_opts do |buffer, bytes|
200
- yield buffer, bytes
201
- end
202
- end
203
-
204
- def size
205
- @object.content_length
206
- end
207
-
208
- def close
209
- @r_buffer.close
210
- @w_buffer.close
211
- @buffer_thread.exit if @buffer_thread
212
- end
213
- end
214
- end
215
- end
216
- end