Skip to content

Instantly share code, notes, and snippets.

@glucero
Last active December 20, 2015 17:09
Show Gist options
  • Save glucero/6166501 to your computer and use it in GitHub Desktop.
Save glucero/6166501 to your computer and use it in GitHub Desktop.
self extracting ruby archiver
#!/usr/bin/env ruby
class RubyArchive
require 'rubygems/package'
require 'zlib'
attr_reader :path
class Archive
def initialize(path, object)
@path = path
@object = object
@data, @tar = StringIO.new, StringIO.new
end
def empty?
@object.size.zero?
end
def compressed_files
Gem::Package::TarReader.new(Zlib::GzipReader.new @object).tap(&:rewind)
end
def uncompressed_files
Dir.glob(File.join @path, '{,**/{*,.*}}').map &File.method(:open)
end
def make_dir(directory)
Dir.mkdir File.join(@path, directory.full_name), directory.header.mode
end
def make_file(file)
File.open(File.join(@path, file.full_name), 'wb') do |f|
f.write file.read
f.chmod file.header.mode
end
end
def add_dir(directory)
tar_writer.mkdir directory.path, directory.stat.mode
end
def add_file(file)
tar_writer.add_file(file.path, file.stat.mode) { |f| f.write file.read }
end
def finalize
@tar.seek 0
gzip_writer.write @tar.read
@tar.close
gzip_writer.finish
@data.seek 0
end
def write
File.open(filename, 'wb') do |file|
file.write File.read(__FILE__)
file.write @data.read
file.chmod 0o755
end
end
def filename
@path.gsub(/\//, '') + '-archive.rb'
end
def gzip_writer
@gzip_writer ||= Zlib::GzipWriter.new(@data)
end
def tar_writer
@tar_writer ||= Gem::Package::TarWriter.new(@tar)
end
end
def initialize(path)
@path = path
@archive = Archive.new @path, StringIO.new(DATA.read)
yield self
end
def usage
@archive.empty? ? 'dir_or_file_to_compress' : 'dir_to_decompress_archive_to'
end
def run
@archive.empty? ? compress : decompress
end
def decompress
@archive.compressed_files.each do |object|
if object.directory?
@archive.make_dir object
else
@archive.make_file object
end
end
system "ls -la #@path" # change me to turn this into an installer
puts 'Extraction complete.'
end
def compress
@archive.uncompressed_files.each do |object|
if File.directory? object
@archive.add_dir object
else
@archive.add_file object
end
end
@archive.finalize
@archive.write
puts 'Compression complete.'
end
def self.start(path)
new(path) do |ruby_archive|
if ruby_archive.path
ruby_archive.run
else
puts %|usage: #{__FILE__} /path/to/#{ruby_archive.usage}|
end
end
end
end
RubyArchive.start ARGV.shift
__END__
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment