Skip to content

Commit

Permalink
use libarchive by preference
Browse files Browse the repository at this point in the history
Signed-off-by: Thom May <thom@chef.io>
  • Loading branch information
Thom May committed Apr 25, 2018
1 parent aea48e9 commit e8795f0
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 16 deletions.
10 changes: 7 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ sudo: false
language: ruby
cache: bundler

addons:
apt:
packages:
- libarchive-dev

matrix:
include:
- rvm: 2.3.6
- rvm: 2.4.3
- rvm: 2.5.0
- rvm: 2.4.4
- rvm: 2.5.1
- rvm: ruby-head
allow_failures:
- rvm: ruby-head
Expand Down
4 changes: 1 addition & 3 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,4 @@ source "https://rubygems.org"
# Specify your gem's dependencies in mixlib-archive.gemspec
gemspec

group(:changelog) do
gem "github_changelog_generator", git: "https://github.com/chef/github-changelog-generator"
end
gem "ffi-libarchive"
10 changes: 8 additions & 2 deletions lib/mixlib/archive.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@ def initialize(archive, empty: false)
@empty = empty

archive = File.expand_path(archive)
# for now we only support Tar format archives.
@archiver = Mixlib::Archive::Tar.new(archive)
begin
# we prefer to use libarchive, which supports a great big pile o' stuff
require "mixlib/archive/lib_archive"
@archiver = Mixlib::Archive::LibArchive.new(archive)
rescue LoadError
# but if we can't use that, we'll fall back to ruby's native tar implementation
@archiver = Mixlib::Archive::Tar.new(archive)
end
end

class Log
Expand Down
63 changes: 63 additions & 0 deletions lib/mixlib/archive/lib_archive.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
require "ffi-libarchive"

module Mixlib
class Archive
class LibArchive
attr_reader :options
attr_reader :archive

def initialize(archive, options = {})
@archive = archive
@options = options
end

# Extracts the archive to the given +destination+
#
# === Parameters
# perms<Boolean>:: should the extracter use permissions from the archive.
# ignore[Array]:: an array of matches of file paths to ignore
def extract(destination, perms: true, ignore: [])
ignore_re = Regexp.union(ignore)
flags = perms ? ::Archive::EXTRACT_PERM : nil
Dir.chdir(destination) do
reader = ::Archive::Reader.open_filename(@archive)

reader.each_entry do |entry|
if entry.pathname =~ ignore_re
Mixlib::Archive::Log.warn "ignoring entry #{entry.pathname}"
next
end

reader.extract(entry, flags.to_i)
end
reader.close
end
end

# Creates an archive with the given set of +files+
#
# === Parameters
# gzip<Boolean>:: should the archive be gzipped?
def create(files, gzip: false)
compression = gzip ? ::Archive::COMPRESSION_GZIP : ::Archive::COMPRESSION_NONE
# "PAX restricted" will use PAX extensions when it has to, but will otherwise
# use ustar for maximum compatibility
format = ::Archive::FORMAT_TAR_PAX_RESTRICTED

::Archive.write_open_filename(archive, compression, format) do |tar|
files.each do |fn|
tar.new_entry do |entry|
entry.pathname = fn
entry.copy_stat(fn)
tar.write_header(entry)
if File.file?(fn)
content = File.read(fn)
tar.write_data(content)
end
end
end
end
end
end
end
end
4 changes: 2 additions & 2 deletions lib/mixlib/archive/tar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,11 @@ def reader(&block)
ensure
if file
file.close unless file.closed?
file = nil
file = nil # rubocop:disable Lint/UselessAssignment
end
if raw
raw.close unless raw.closed?
raw = nil
raw = nil # rubocop:disable Lint/UselessAssignment
end
end

Expand Down
15 changes: 9 additions & 6 deletions spec/mixlib/archive_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@

describe Mixlib::Archive do
let(:target) { "../fixtures/foo.tar" }
let (:destination) { Dir.mktmpdir }
let (:files) { %w{ file dir/file new_file.rb } }
let(:destination) { ::Dir.mktmpdir }
let(:files) { %w{ file dir/file new_file.rb } }

let (:archive) { described_class.new(target) }
let (:archiver) { double(Mixlib::Archive::Tar, extract: true) }
let(:archive) { described_class.new(target) }
let(:tar_archiver) { double(Mixlib::Archive::Tar, extract: true) }
let(:archiver) { double(Mixlib::Archive::LibArchive, extract: true) }

before do
allow(File).to receive(:expand_path).and_call_original
allow(Mixlib::Archive::Tar).to receive(:new).with(any_args).and_return(archiver)
allow(Mixlib::Archive::LibArchive).to receive(:new).with(any_args).and_return(archiver)
end

after do
Expand All @@ -31,11 +33,12 @@
before do
end

it "with the correct archiver" do
it "with the default archiver" do
expect(File).to receive(:expand_path).with(target).and_return(expanded_target)
expect(Mixlib::Archive::Tar).to receive(:new).with(expanded_target)
expect(Mixlib::Archive::LibArchive).to receive(:new).with(expanded_target)
described_class.new(target)
end

end
end

Expand Down
3 changes: 3 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
require "tmpdir"
require "mixlib/archive"
require "mixlib/archive/tar"
require "mixlib/archive/lib_archive"

0 comments on commit e8795f0

Please sign in to comment.