From 589c5b4e8dc4fab625868672d138e46290b19ecf Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 16 Jul 2018 19:00:49 +0200 Subject: [PATCH 1/6] Add support for nested archives. --- Library/Homebrew/test/unpack_strategy_spec.rb | 23 +++++++++++ Library/Homebrew/unpack_strategy.rb | 38 +++++++++++++++---- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/Library/Homebrew/test/unpack_strategy_spec.rb b/Library/Homebrew/test/unpack_strategy_spec.rb index c24e417309..69efd7d886 100644 --- a/Library/Homebrew/test/unpack_strategy_spec.rb +++ b/Library/Homebrew/test/unpack_strategy_spec.rb @@ -15,6 +15,29 @@ RSpec.shared_examples "#extract" do |children: []| end end +describe UnpackStrategy do + describe "#extract_nestedly" do + let(:file_name) { "file" } + let(:nested_archive) { + dir = mktmpdir + + (dir/"file").write "This file was inside a GZIP inside a BZIP2." + system "gzip", dir.children.first + system "bzip2", dir.children.first + + dir.children.first + } + let(:unpack_dir) { mktmpdir } + subject(:strategy) { described_class.detect(nested_archive) } + + it "can extract nested archives" do + strategy.extract_nestedly(to: unpack_dir) + + expect(File.read(unpack_dir/file_name)).to eq("This file was inside a GZIP inside a BZIP2.") + end + end +end + describe UncompressedUnpackStrategy do let(:path) { (mktmpdir/"test").tap do |path| diff --git a/Library/Homebrew/unpack_strategy.rb b/Library/Homebrew/unpack_strategy.rb index 96c0f14ce6..657e89bc1e 100644 --- a/Library/Homebrew/unpack_strategy.rb +++ b/Library/Homebrew/unpack_strategy.rb @@ -67,6 +67,30 @@ class UnpackStrategy unpack_dir.mkpath extract_to_dir(unpack_dir, basename: basename) end + + def extract_nestedly(to: nil, basename: nil) + if is_a?(UncompressedUnpackStrategy) + extract(to: to, basename: basename) + return + end + + Dir.mktmpdir do |tmp_unpack_dir| + tmp_unpack_dir = Pathname(tmp_unpack_dir) + + extract(to: tmp_unpack_dir, basename: basename) + + children = tmp_unpack_dir.children + + if children.count == 1 + s = self.class.detect(children.first) + + s.extract_nestedly(to: to, basename: basename) + next + end + + DirectoryUnpackStrategy.new(tmp_unpack_dir).extract(to: to) + end + end end class DirectoryUnpackStrategy < UnpackStrategy @@ -166,7 +190,7 @@ class CompressUnpackStrategy < TarUnpackStrategy end end -class XzUnpackStrategy < UncompressedUnpackStrategy +class XzUnpackStrategy < UnpackStrategy def self.can_extract?(path:, magic_number:) magic_number.match?(/\A\xFD7zXZ\x00/n) end @@ -192,7 +216,7 @@ class XzUnpackStrategy < UncompressedUnpackStrategy end end -class Bzip2UnpackStrategy < UncompressedUnpackStrategy +class Bzip2UnpackStrategy < UnpackStrategy def self.can_extract?(path:, magic_number:) magic_number.match?(/\ABZh/n) end @@ -200,12 +224,12 @@ class Bzip2UnpackStrategy < UncompressedUnpackStrategy private def extract_to_dir(unpack_dir, basename:) - super + FileUtils.cp path, unpack_dir/basename, preserve: true safe_system "bunzip2", "-q", unpack_dir/basename end end -class GzipUnpackStrategy < UncompressedUnpackStrategy +class GzipUnpackStrategy < UnpackStrategy def self.can_extract?(path:, magic_number:) magic_number.match?(/\A\037\213/n) end @@ -213,12 +237,12 @@ class GzipUnpackStrategy < UncompressedUnpackStrategy private def extract_to_dir(unpack_dir, basename:) - super + FileUtils.cp path, unpack_dir/basename, preserve: true safe_system "gunzip", "-q", "-N", unpack_dir/basename end end -class LzipUnpackStrategy < UncompressedUnpackStrategy +class LzipUnpackStrategy < UnpackStrategy def self.can_extract?(path:, magic_number:) magic_number.match?(/\ALZIP/n) end @@ -226,7 +250,7 @@ class LzipUnpackStrategy < UncompressedUnpackStrategy private def extract_to_dir(unpack_dir, basename:) - super + FileUtils.cp path, unpack_dir/basename, preserve: true safe_system Formula["lzip"].opt_bin/"lzip", "-d", "-q", unpack_dir/basename end end From c5b1bb93776fdc997e98e815dbd7d63ab8591151 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 16 Jul 2018 19:40:29 +0200 Subject: [PATCH 2/6] Use `unxz` instead of `xz -d`. --- Library/Homebrew/unpack_strategy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/unpack_strategy.rb b/Library/Homebrew/unpack_strategy.rb index 657e89bc1e..8274dea20a 100644 --- a/Library/Homebrew/unpack_strategy.rb +++ b/Library/Homebrew/unpack_strategy.rb @@ -199,7 +199,7 @@ class XzUnpackStrategy < UnpackStrategy def extract_to_dir(unpack_dir, basename:) super - safe_system Formula["xz"].opt_bin/"xz", "-d", "-q", "-T0", unpack_dir/basename + safe_system Formula["xz"].opt_bin/"unxz", "-q", "-T0", unpack_dir/basename extract_nested_tar(unpack_dir, basename: basename) end From a6aefb43c57a27dd38370a55e9eba269ed8b8890 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 16 Jul 2018 20:10:22 +0200 Subject: [PATCH 3/6] =?UTF-8?q?Don=E2=80=99t=20recurse=20into=20nested=20d?= =?UTF-8?q?irectories.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Library/Homebrew/unpack_strategy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/unpack_strategy.rb b/Library/Homebrew/unpack_strategy.rb index 8274dea20a..adbcc959dc 100644 --- a/Library/Homebrew/unpack_strategy.rb +++ b/Library/Homebrew/unpack_strategy.rb @@ -81,7 +81,7 @@ class UnpackStrategy children = tmp_unpack_dir.children - if children.count == 1 + if children.count == 1 && !children.first.directory? s = self.class.detect(children.first) s.extract_nestedly(to: to, basename: basename) From 95b0b198a5e584c5845557713fed4cbafe5e902f Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 16 Jul 2018 20:18:29 +0200 Subject: [PATCH 4/6] Remove redundant `extract_to_dir`. --- Library/Homebrew/unpack_strategy.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Library/Homebrew/unpack_strategy.rb b/Library/Homebrew/unpack_strategy.rb index adbcc959dc..57ee57ab67 100644 --- a/Library/Homebrew/unpack_strategy.rb +++ b/Library/Homebrew/unpack_strategy.rb @@ -295,12 +295,6 @@ class GitUnpackStrategy < DirectoryUnpackStrategy def self.can_extract?(path:, magic_number:) super && (path/".git").directory? end - - private - - def extract_to_dir(unpack_dir, basename:) - FileUtils.cp_r path.children, unpack_dir, preserve: true - end end class SubversionUnpackStrategy < DirectoryUnpackStrategy From 85f76e312a6171dceab69b1163dede2f903092fa Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 16 Jul 2018 20:56:41 +0200 Subject: [PATCH 5/6] Add spec for nested directories. --- Library/Homebrew/test/unpack_strategy_spec.rb | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/Library/Homebrew/test/unpack_strategy_spec.rb b/Library/Homebrew/test/unpack_strategy_spec.rb index 69efd7d886..4d31c76045 100644 --- a/Library/Homebrew/test/unpack_strategy_spec.rb +++ b/Library/Homebrew/test/unpack_strategy_spec.rb @@ -17,23 +17,44 @@ end describe UnpackStrategy do describe "#extract_nestedly" do - let(:file_name) { "file" } - let(:nested_archive) { - dir = mktmpdir + subject(:strategy) { described_class.detect(path) } - (dir/"file").write "This file was inside a GZIP inside a BZIP2." - system "gzip", dir.children.first - system "bzip2", dir.children.first - - dir.children.first - } let(:unpack_dir) { mktmpdir } - subject(:strategy) { described_class.detect(nested_archive) } - it "can extract nested archives" do - strategy.extract_nestedly(to: unpack_dir) + context "when extracting a GZIP nested in a BZIP2" do + let(:file_name) { "file" } + let(:path) { + dir = mktmpdir - expect(File.read(unpack_dir/file_name)).to eq("This file was inside a GZIP inside a BZIP2.") + (dir/"file").write "This file was inside a GZIP inside a BZIP2." + system "gzip", dir.children.first + system "bzip2", dir.children.first + + dir.children.first + } + + it "can extract nested archives" do + strategy.extract_nestedly(to: unpack_dir) + + expect(File.read(unpack_dir/file_name)).to eq("This file was inside a GZIP inside a BZIP2.") + end + end + + context "when extracting a directory with nested directories" do + let(:directories) { "A/B/C" } + let(:path) { + (mktmpdir/"file.tar").tap do |path| + mktmpdir do |dir| + (dir/directories).mkpath + system "tar", "-c", "-f", path, "-C", dir, "A/" + end + end + } + + it "does not recurse into nested directories" do + strategy.extract_nestedly(to: unpack_dir) + expect(Pathname.glob(unpack_dir/"**/*")).to include unpack_dir/directories + end end end end From 954edb288572d0b054aca985f6702d7cad606ab6 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 16 Jul 2018 21:36:18 +0200 Subject: [PATCH 6/6] Alias `extract_nestedly` to `extract` for uncompressed files. --- Library/Homebrew/unpack_strategy.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Library/Homebrew/unpack_strategy.rb b/Library/Homebrew/unpack_strategy.rb index 57ee57ab67..84def55eb9 100644 --- a/Library/Homebrew/unpack_strategy.rb +++ b/Library/Homebrew/unpack_strategy.rb @@ -69,11 +69,6 @@ class UnpackStrategy end def extract_nestedly(to: nil, basename: nil) - if is_a?(UncompressedUnpackStrategy) - extract(to: to, basename: basename) - return - end - Dir.mktmpdir do |tmp_unpack_dir| tmp_unpack_dir = Pathname(tmp_unpack_dir) @@ -106,6 +101,8 @@ class DirectoryUnpackStrategy < UnpackStrategy end class UncompressedUnpackStrategy < UnpackStrategy + alias extract_nestedly extract + private def extract_to_dir(unpack_dir, basename:)