Class: Zipping::ZipBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/zipping.rb

Instance Method Summary collapse

Constructor Details

#initialize(output_stream, file_division_size = 1048576, encoding = :utf8) ⇒ ZipBuilder

Initialize ZipBuilder. ‘files’ must be a String(file or directory path), a Hash(entity), or an Array of Strings and/or Hashes.



94
95
96
97
98
# File 'lib/zipping.rb', line 94

def initialize(output_stream, file_division_size = 1048576, encoding = :utf8)
  @w = Writer.new output_stream, file_division_size
  @e = encoding
  @l = []
end

Instance Method Details

#abs_path_for(name) ⇒ Object



144
145
146
# File 'lib/zipping.rb', line 144

def abs_path_for(name)
  root_dir? ? name : (@current_dir[:abs_path] + '/' + name)
end

#abs_path_for_entity(entity) ⇒ Object



148
149
150
# File 'lib/zipping.rb', line 148

def abs_path_for_entity(entity)
  abs_path_for entity[:name] || File.basename(entity[:path])
end

#cd(dir) ⇒ Object



128
129
130
# File 'lib/zipping.rb', line 128

def cd(dir)
  @current_dir = dir
end

#closeObject

Create central directories



224
225
226
227
# File 'lib/zipping.rb', line 224

def close
  pack_symlinks
  @w.close
end

#current_dirObject



136
137
138
# File 'lib/zipping.rb', line 136

def current_dir
  root_dir? ? '' : @current_dir[:abs_path]
end

#current_dir_entityObject



140
141
142
# File 'lib/zipping.rb', line 140

def current_dir_entity
  @current_dir
end

#fix_current_dir_entityObject



169
170
171
172
173
174
175
176
# File 'lib/zipping.rb', line 169

def fix_current_dir_entity
  fix_entity(@current_dir).merge!(
    {
      binary_name: string_to_bytes(@current_dir[:abs_path] + '/'),
      zip_path: @current_dir[:abs_path]
    }
  )
end

#fix_entity(entity) ⇒ Object

Fix an entity: time -> DOSTime object, name -> abs path in zip & encoded



160
161
162
163
164
165
166
167
# File 'lib/zipping.rb', line 160

def fix_entity(entity)
  {
    path: entity[:path],
    filetime: Zip::DOSTime.at(entity[:time] || File.mtime(entity[:path])),
    binary_name: string_to_bytes(abs_path_for_entity(entity)),
    zip_path: abs_path_for_entity(entity)
  }
end

#has_dir?Boolean

Returns:

  • (Boolean)


107
108
109
# File 'lib/zipping.rb', line 107

def has_dir?
  ! @pending_dirs.empty?
end

#next_dirObject



111
112
113
# File 'lib/zipping.rb', line 111

def next_dir
  @pending_dirs.shift
end

#pack(files) ⇒ Object

Pack file and directory entities and output to stream.



194
195
196
197
198
199
200
201
202
203
204
# File 'lib/zipping.rb', line 194

def pack(files)
  entities = Entity.entities_from files
  return if entities.empty?

  reset_state
  pack_entities entities
  while has_dir?
    cd next_dir
    pack_current_dir
  end
end

#pack_current_dirObject

Pack a directory



207
208
209
210
# File 'lib/zipping.rb', line 207

def pack_current_dir
  pack_current_directory_entity
  pack_entities subdir_entities
end

#pack_current_directory_entityObject



258
259
260
261
# File 'lib/zipping.rb', line 258

def pack_current_directory_entity
  @w.load_entity fix_current_dir_entity
  @w.write_directory_entry
end

#pack_entities(entities) ⇒ Object

Pack file entities. Directory entities are queued, not packed in this method.



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/zipping.rb', line 230

def pack_entities(entities)
  entities.each do |entity|
    # ignore bad entities
    next unless entity.is_a?(Hash) && entity[:path]

    path = entity[:path]
    if File.symlink? path
      postpone_symlink entity
    elsif File.directory? path
      postpone_dir entity
    elsif File.file? path
      pack_file_entity entity
    end
  end
end

#pack_entity(entity) ⇒ Object



263
264
265
266
# File 'lib/zipping.rb', line 263

def pack_entity(entity)
  @w.load_entity fix_entity entity
  yield
end

#pack_file_entity(entity) ⇒ Object



246
247
248
249
250
# File 'lib/zipping.rb', line 246

def pack_file_entity(entity)
  pack_entity entity do
    @w.write_file_entry
  end
end


252
253
254
255
256
# File 'lib/zipping.rb', line 252

def pack_symbolic_link_entity(entity)
  pack_entity entity do
    @w.write_symbolic_link_entry
  end
end

Pack symlinks if its link path exists in zip



213
214
215
216
217
218
219
220
221
# File 'lib/zipping.rb', line 213

def pack_symlinks
  reset_state
  @l.each do |link|
    if @w.path_exists? Entity.linked_path(link[:abs_path], File.readlink(link[:path]))
      link[:name] = link[:abs_path]
      pack_symbolic_link_entity link
    end
  end
end

#postpone_dir(dir) ⇒ Object



115
116
117
# File 'lib/zipping.rb', line 115

def postpone_dir(dir)
  queue_entity dir, @pending_dirs
end


119
120
121
# File 'lib/zipping.rb', line 119

def postpone_symlink(link)
  queue_entity link, @l
end

#queue_entity(entity, queue) ⇒ Object



123
124
125
126
# File 'lib/zipping.rb', line 123

def queue_entity(entity, queue)
  entity[:abs_path] = abs_path_for entity[:name] || File.basename(entity[:path])
  queue << entity
end

#reset_stateObject

Attr controls



102
103
104
105
# File 'lib/zipping.rb', line 102

def reset_state
  @pending_dirs = []
  @current_dir = {name: '', time: Time.now}
end

#root_dir?Boolean

Returns:

  • (Boolean)


132
133
134
# File 'lib/zipping.rb', line 132

def root_dir?
  @current_dir.nil? || @current_dir[:abs_path].nil?
end

#string_to_bytes(str) ⇒ Object

Create ASCII-8bits string. Also convert encoding if needed.



179
180
181
182
183
184
185
186
187
188
189
# File 'lib/zipping.rb', line 179

def string_to_bytes(str)
  unless @e.nil? || @e == :utf8
    if @e == :shift_jis
      begin
        str = str.encode 'Shift_JIS', :invalid => :replace, :undef => :replace, :replace => '??'
      rescue => e
      end
    end
  end
  [str].pack('a*')
end

#subdir_entities(dir = @current_dir) ⇒ Object

Get entities of files in dir



155
156
157
# File 'lib/zipping.rb', line 155

def subdir_entities(dir = @current_dir)
  Dir.glob(dir[:path] + '/*').map!{|path| {path: path, time: File.mtime(path), name: File.basename(path)}}
end