blob: 77cc44c7d32eb462dac4eae6adfd9213e42b28ff (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
# frozen_string_literal: true
require 'open3'
require 'shellwords'
module Axlsx
# The ZipCommand class supports zipping the Excel file contents using
# a binary zip program instead of RubyZip's `Zip::OutputStream`.
#
# The methods provided here mimic `Zip::OutputStream` so that `ZipCommand` can
# be used as a drop-in replacement. Note that method signatures are not
# identical to `Zip::OutputStream`, they are only sufficiently close so that
# `ZipCommand` and `Zip::OutputStream` can be interchangeably used within
# `caxlsx`.
class ZipCommand
# Raised when the zip command exits with a non-zero status.
class ZipError < StandardError; end
def initialize(zip_command)
@current_file = nil
@files = []
@zip_command = zip_command
end
# Create a temporary directory for writing files to.
#
# The directory and its contents are removed at the end of the block.
def open(output)
Dir.mktmpdir do |dir|
@dir = dir
yield(self)
write_file
zip_parts(output)
end
end
# Closes the current entry and opens a new for writing.
def put_next_entry(entry)
write_file
@current_file = "#{@dir}/#{entry.name}"
@files << entry.name
FileUtils.mkdir_p(File.dirname(@current_file))
@io = File.open(@current_file, "wb")
end
# Write to a buffer that will be written to the current entry
def write(content)
@io << content
end
alias << write
private
def write_file
@io.close if @current_file
@current_file = nil
@io = nil
end
def zip_parts(output)
output = Shellwords.shellescape(File.absolute_path(output))
inputs = Shellwords.shelljoin(@files)
escaped_dir = Shellwords.shellescape(@dir)
command = "cd #{escaped_dir} && #{@zip_command} #{output} #{inputs}"
stdout_and_stderr, status = Open3.capture2e(command)
unless status.success?
raise ZipError, stdout_and_stderr
end
end
end
end
|