Skip to content

Commit 5530edb

Browse files
authored
Add batch command for BYO snapshots (#57)
1 parent 847463e commit 5530edb

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

lib/commands/upload/snapshots/snapshots.rb

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
require 'async/barrier'
77
require 'async/semaphore'
88
require 'async/http/internet/instance'
9+
require 'zip'
10+
require 'tempfile'
911

1012
module EmergeCLI
1113
module Commands
@@ -33,6 +35,8 @@ class Snapshots < EmergeCLI::Commands::GlobalOptions
3335

3436
option :profile, type: :boolean, default: false, desc: 'Enable performance profiling metrics'
3537

38+
option :batch, type: :boolean, default: false, desc: 'Upload images in batch using zip file'
39+
3640
argument :image_paths, type: :array, required: false, desc: 'Paths to folders containing images'
3741

3842
def initialize(network: nil, git_info_provider: nil)
@@ -178,6 +182,86 @@ def create_run
178182
def upload_images(run_id, concurrency, image_files, client)
179183
Logger.info 'Uploading images...'
180184

185+
if @options[:batch]
186+
batch_upload_images(run_id, image_files, client)
187+
else
188+
individual_upload_images(run_id, concurrency, image_files, client)
189+
end
190+
end
191+
192+
def batch_upload_images(run_id, image_files, client)
193+
Logger.info 'Preparing batch upload...'
194+
195+
metadata_barrier = Async::Barrier.new
196+
metadata_semaphore = Async::Semaphore.new(10, parent: metadata_barrier)
197+
198+
image_metadata = {
199+
manifestVersion: 1,
200+
images: {},
201+
errors: []
202+
}
203+
204+
@profiler.measure('process_image_metadata') do
205+
image_files.each do |image_path|
206+
metadata_semaphore.async do
207+
file_info = client.parse_file_info(image_path)
208+
209+
dimensions = @profiler.measure('chunky_png_processing') do
210+
datastream = ChunkyPNG::Datastream.from_file(image_path)
211+
{
212+
width: datastream.header_chunk.width,
213+
height: datastream.header_chunk.height
214+
}
215+
end
216+
217+
metadata = {
218+
fileName: file_info[:file_name],
219+
groupName: file_info[:group_name],
220+
displayName: file_info[:variant_name],
221+
width: dimensions[:width],
222+
height: dimensions[:height]
223+
}
224+
225+
image_name = File.basename(image_path, '.*')
226+
image_metadata[:images][image_name] = metadata
227+
end
228+
end
229+
230+
metadata_barrier.wait
231+
end
232+
233+
Tempfile.create(['snapshot_batch', '.zip']) do |zip_file|
234+
@profiler.measure('create_zip_file') do
235+
Zip::File.open(zip_file.path, Zip::File::CREATE) do |zipfile|
236+
zipfile.get_output_stream('manifest.json') { |f| f.write(JSON.generate(image_metadata)) }
237+
238+
image_files.each do |image_path|
239+
image_name = File.basename(image_path)
240+
zipfile.add(image_name, image_path)
241+
end
242+
end
243+
end
244+
245+
upload_url = @profiler.measure('create_batch_upload_url') do
246+
response = @network.post(path: '/v1/snapshots/run/batch-image', body: { run_id: run_id })
247+
JSON.parse(response.read).fetch('zip_url')
248+
end
249+
250+
Logger.info 'Uploading images...'
251+
Logger.debug "Uploading batch zip file to #{upload_url}"
252+
@profiler.measure('upload_batch_zip') do
253+
@network.put(
254+
path: upload_url,
255+
headers: { 'Content-Type' => 'application/zip' },
256+
body: File.read(zip_file.path)
257+
)
258+
end
259+
end
260+
ensure
261+
metadata_barrier&.stop
262+
end
263+
264+
def individual_upload_images(run_id, concurrency, image_files, client)
181265
post_image_barrier = Async::Barrier.new
182266
post_image_semaphore = Async::Semaphore.new(concurrency, parent: post_image_barrier)
183267

0 commit comments

Comments
 (0)