Module: MultiZip::Backend::ArchiveZip

Defined in:
lib/multi_zip/backend/archive_zip.rb

Constant Summary collapse

BUFFER_SIZE =
8192

Instance Method Summary collapse

Instance Method Details

#extract_member(member_path, destination_path, options = {}) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/multi_zip/backend/archive_zip.rb', line 50

def extract_member(member_path, destination_path, options = {}) 
  archive_operation do |zip|
    member = zip.find{|m| m.zip_path == member_path}
    if member && member.file?
      output_file = ::File.new(destination_path, 'wb')
      while chunk = member.file_data.read(BUFFER_SIZE)
        output_file.write chunk
      end
      output_file.close
      return destination_path
    else
      zip.close
      member_not_found!(member_path)
    end
  end
end

#list_members(prefix = nil, options = {}) ⇒ Object



16
17
18
19
20
21
22
# File 'lib/multi_zip/backend/archive_zip.rb', line 16

def list_members(prefix=nil, options={})
  archive_operation do |zip|
    zip.entries.map(&:zip_path).select{|n|
      prefix ? n =~ /^#{prefix}/ : true
    }.sort
  end
end

#read_member(member_path, options = {}) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
# File 'lib/multi_zip/backend/archive_zip.rb', line 4

def read_member(member_path, options = {})
  archive_operation do |zip|
    member = zip.find{|m| m.zip_path == member_path}
    if member && member.file?
      return member.file_data.read.to_s
    else
      zip.close
      member_not_found!(member_path)
    end
  end
end

#remove_member(member_path, options = {}) ⇒ Object



67
68
69
# File 'lib/multi_zip/backend/archive_zip.rb', line 67

def remove_member(member_path, options = {})
  remove_members([member_path], options)
end

#remove_members(member_paths, options = {}) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/multi_zip/backend/archive_zip.rb', line 71

def remove_members(member_paths, options = {})
  archive_exists!
  member_paths.each do |member_path|
    exists!(member_path)
  end
  
  # archive-zip doesn't have the #remove_entry method any more, so we do
  # this in a really slow way: we dump the entire dir to the filesystem,
  # delete `member_path` and zip the whole thing up again.
  
  Dir.mktmpdir do |tmp_dir|
    Archive::Zip.extract(@filename, tmp_dir)

    member_paths.each do |member_path|
      FileUtils.rm("#{tmp_dir}/#{member_path}")
    end
    
    # create a tempfile and immediately delete it, we just want the name.
    tempfile = Tempfile.new(['multizip_temp', '.zip'])
    tempfile_path = tempfile.path
    tempfile.close
    tempfile.delete

    Archive::Zip.archive(tempfile_path, "#{tmp_dir}/.")
    FileUtils.mv(tempfile_path, @filename)
  end

  true
end

#write_member(member_path, member_contents, options = {}) ⇒ Object



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
# File 'lib/multi_zip/backend/archive_zip.rb', line 24

def write_member(member_path, member_contents, options = {})
  # archive/zip is really focused on adding content from the file system so
  # instead of hacking around with a non-public API that may change in the
  # future, we will just use tempfiles and let it read from disk like the
  # documentation says.
  tempfile = Tempfile.new('multizip_member')
  tempfile.write(member_contents)
  tempfile.close
  
  zip = Archive::Zip.new(@filename, :w)
  new_entry = Archive::Zip::Entry.from_file(tempfile.path, :zip_path => member_path)
  zip.add_entry(new_entry)

  # From the docs: The #close method must be called in order to save any
  # modifications to the archive.  Due to limitations in the Ruby finalization
  # capabilities, the #close method is _not_ automatically called when this
  # object is garbage collected.  Make sure to call #close when finished with
  # this object.
  zip.close
  true
ensure
  if defined?(tempfile)
    tempfile.delete
  end
end