| 
									
										
										
										
											2020-10-10 14:16:11 +02:00
										 |  |  | # typed: false | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  | require "system_command" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-09 06:09:05 +02:00
										 |  |  | # Module containing all available strategies for unpacking archives. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # @api private | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  | module UnpackStrategy | 
					
						
							| 
									
										
										
										
											2020-10-20 00:56:50 +02:00
										 |  |  |   extend T::Sig | 
					
						
							|  |  |  |   extend T::Helpers | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  |   include SystemCommand::Mixin | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-09 06:09:05 +02:00
										 |  |  |   # Helper module for identifying the file type. | 
					
						
							| 
									
										
										
										
											2018-07-29 10:04:51 +02:00
										 |  |  |   module Magic | 
					
						
							| 
									
										
										
										
											2020-08-09 06:09:05 +02:00
										 |  |  |     # Length of the longest regex (currently Tar). | 
					
						
							| 
									
										
										
										
											2018-07-29 10:04:51 +02:00
										 |  |  |     MAX_MAGIC_NUMBER_LENGTH = 262
 | 
					
						
							| 
									
										
										
										
											2020-10-20 00:56:50 +02:00
										 |  |  |     private_constant :MAX_MAGIC_NUMBER_LENGTH | 
					
						
							| 
									
										
										
										
											2018-07-29 10:04:51 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     refine Pathname do | 
					
						
							|  |  |  |       def magic_number | 
					
						
							|  |  |  |         @magic_number ||= if directory? | 
					
						
							|  |  |  |           "" | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           binread(MAX_MAGIC_NUMBER_LENGTH) || "" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def file_type | 
					
						
							|  |  |  |         @file_type ||= system_command("file", args: ["-b", self], print_stderr: false) | 
					
						
							|  |  |  |                        .stdout.chomp | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def zipinfo | 
					
						
							|  |  |  |         @zipinfo ||= system_command("zipinfo", args: ["-1", self], print_stderr: false) | 
					
						
							|  |  |  |                      .stdout | 
					
						
							|  |  |  |                      .encode(Encoding::UTF_8, invalid: :replace) | 
					
						
							|  |  |  |                      .split("\n") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  |   private_constant :Magic | 
					
						
							| 
									
										
										
										
											2018-07-01 23:35:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def self.strategies | 
					
						
							|  |  |  |     @strategies ||= [ | 
					
						
							| 
									
										
										
										
											2021-09-16 15:56:31 +01:00
										 |  |  |       Tar, # Needs to be before Bzip2/Gzip/Xz/Lzma/Zstd. | 
					
						
							| 
									
										
										
										
											2018-09-11 19:21:18 +02:00
										 |  |  |       Pax, | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  |       Gzip, | 
					
						
							| 
									
										
										
										
											2020-11-17 09:12:32 +00:00
										 |  |  |       Dmg, # Needs to be before Bzip2/Xz/Lzma. | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  |       Lzma, | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  |       Xz, | 
					
						
							| 
									
										
										
										
											2021-09-16 15:56:31 +01:00
										 |  |  |       Zstd, | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  |       Lzip, | 
					
						
							| 
									
										
										
										
											2020-08-09 06:09:05 +02:00
										 |  |  |       Air, # Needs to be before `Zip`. | 
					
						
							|  |  |  |       Jar, # Needs to be before `Zip`. | 
					
						
							|  |  |  |       LuaRock, # Needs to be before `Zip`. | 
					
						
							|  |  |  |       MicrosoftOfficeXml, # Needs to be before `Zip`. | 
					
						
							| 
									
										
										
										
											2018-07-29 10:33:47 +02:00
										 |  |  |       Zip, | 
					
						
							| 
									
										
										
										
											2020-08-09 06:09:05 +02:00
										 |  |  |       Pkg, # Needs to be before `Xar`. | 
					
						
							| 
									
										
										
										
											2018-07-29 10:33:47 +02:00
										 |  |  |       Xar, | 
					
						
							|  |  |  |       Ttf, | 
					
						
							|  |  |  |       Otf, | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  |       Git, | 
					
						
							|  |  |  |       Mercurial, | 
					
						
							|  |  |  |       Subversion, | 
					
						
							|  |  |  |       Cvs, | 
					
						
							| 
									
										
										
										
											2020-08-09 06:09:05 +02:00
										 |  |  |       SelfExtractingExecutable, # Needs to be before `Cab`. | 
					
						
							| 
									
										
										
										
											2018-07-30 09:49:59 +02:00
										 |  |  |       Cab, | 
					
						
							|  |  |  |       Executable, | 
					
						
							| 
									
										
										
										
											2018-07-25 23:34:17 +02:00
										 |  |  |       Bzip2, | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  |       Fossil, | 
					
						
							|  |  |  |       Bazaar, | 
					
						
							| 
									
										
										
										
											2018-07-27 11:42:34 +02:00
										 |  |  |       Compress, | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  |       P7Zip, | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  |       Sit, | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  |       Rar, | 
					
						
							|  |  |  |       Lha, | 
					
						
							| 
									
										
										
										
											2018-07-01 23:35:29 +02:00
										 |  |  |     ].freeze | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  |   private_class_method :strategies | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  |   def self.from_type(type) | 
					
						
							|  |  |  |     type = { | 
					
						
							| 
									
										
										
										
											2018-11-02 17:18:07 +00:00
										 |  |  |       naked:     :uncompressed, | 
					
						
							|  |  |  |       nounzip:   :uncompressed, | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  |       seven_zip: :p7zip, | 
					
						
							|  |  |  |     }.fetch(type, type) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     begin | 
					
						
							| 
									
										
										
										
											2018-09-03 21:40:19 +02:00
										 |  |  |       const_get(type.to_s.split("_").map(&:capitalize).join.gsub(/\d+[a-z]/, &:upcase)) | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  |     rescue NameError | 
					
						
							|  |  |  |       nil | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-30 22:23:26 +02:00
										 |  |  |   def self.from_extension(extension) | 
					
						
							| 
									
										
										
										
											2018-09-11 19:21:18 +02:00
										 |  |  |     strategies.sort_by { |s| s.extensions.map(&:length).max || 0 } | 
					
						
							| 
									
										
										
										
											2018-07-30 22:23:26 +02:00
										 |  |  |               .reverse | 
					
						
							| 
									
										
										
										
											2018-09-02 20:14:54 +01:00
										 |  |  |               .find { |s| s.extensions.any? { |ext| extension.end_with?(ext) } } | 
					
						
							| 
									
										
										
										
											2018-07-30 22:23:26 +02:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2018-07-01 23:35:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-30 22:23:26 +02:00
										 |  |  |   def self.from_magic(path) | 
					
						
							| 
									
										
										
										
											2018-09-02 20:14:54 +01:00
										 |  |  |     strategies.find { |s| s.can_extract?(path) } | 
					
						
							| 
									
										
										
										
											2018-07-30 22:23:26 +02:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2018-07-30 09:49:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-09 21:45:35 +00:00
										 |  |  |   def self.detect(path, prioritise_extension: false, type: nil, ref_type: nil, ref: nil, merge_xattrs: nil) | 
					
						
							| 
									
										
										
										
											2018-07-30 22:23:26 +02:00
										 |  |  |     strategy = from_type(type) if type | 
					
						
							| 
									
										
										
										
											2018-07-01 23:35:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-03 10:32:29 +01:00
										 |  |  |     if prioritise_extension && path.extname.present? | 
					
						
							| 
									
										
										
										
											2018-07-30 22:23:26 +02:00
										 |  |  |       strategy ||= from_extension(path.extname) | 
					
						
							|  |  |  |       strategy ||= strategies.select { |s| s < Directory || s == Fossil } | 
					
						
							| 
									
										
										
										
											2018-09-02 20:14:54 +01:00
										 |  |  |                              .find { |s| s.can_extract?(path) } | 
					
						
							| 
									
										
										
										
											2018-07-30 22:23:26 +02:00
										 |  |  |     else | 
					
						
							|  |  |  |       strategy ||= from_magic(path) | 
					
						
							|  |  |  |       strategy ||= from_extension(path.extname) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     strategy ||= Uncompressed | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-09 21:45:35 +00:00
										 |  |  |     strategy.new(path, ref_type: ref_type, ref: ref, merge_xattrs: merge_xattrs) | 
					
						
							| 
									
										
										
										
											2018-07-01 23:35:29 +02:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-09 21:45:35 +00:00
										 |  |  |   attr_reader :path, :merge_xattrs | 
					
						
							| 
									
										
										
										
											2018-07-01 23:35:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-09 21:45:35 +00:00
										 |  |  |   def initialize(path, ref_type: nil, ref: nil, merge_xattrs: nil) | 
					
						
							| 
									
										
										
										
											2018-07-01 23:35:29 +02:00
										 |  |  |     @path = Pathname(path).expand_path | 
					
						
							| 
									
										
										
										
											2018-07-09 22:11:26 +02:00
										 |  |  |     @ref_type = ref_type | 
					
						
							|  |  |  |     @ref = ref | 
					
						
							| 
									
										
										
										
											2019-04-09 21:45:35 +00:00
										 |  |  |     @merge_xattrs = merge_xattrs | 
					
						
							| 
									
										
										
										
											2018-07-01 23:35:29 +02:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 00:56:50 +02:00
										 |  |  |   abstract! | 
					
						
							|  |  |  |   sig { abstract.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) } | 
					
						
							|  |  |  |   def extract_to_dir(unpack_dir, basename:, verbose:); end | 
					
						
							|  |  |  |   private :extract_to_dir | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def extract(to: nil, basename: nil, verbose: nil) | 
					
						
							| 
									
										
										
										
											2018-07-09 20:04:33 +02:00
										 |  |  |     basename ||= path.basename | 
					
						
							| 
									
										
										
										
											2018-07-01 23:35:29 +02:00
										 |  |  |     unpack_dir = Pathname(to || Dir.pwd).expand_path | 
					
						
							|  |  |  |     unpack_dir.mkpath | 
					
						
							| 
									
										
										
										
											2020-10-20 00:56:50 +02:00
										 |  |  |     extract_to_dir(unpack_dir, basename: Pathname(basename), verbose: verbose || false) | 
					
						
							| 
									
										
										
										
											2018-07-01 23:35:29 +02:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2018-07-16 19:00:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-03 10:32:29 +01:00
										 |  |  |   def extract_nestedly(to: nil, basename: nil, verbose: false, prioritise_extension: false) | 
					
						
							| 
									
										
										
										
											2018-07-16 19:00:49 +02:00
										 |  |  |     Dir.mktmpdir do |tmp_unpack_dir| | 
					
						
							|  |  |  |       tmp_unpack_dir = Pathname(tmp_unpack_dir) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-21 16:52:27 +02:00
										 |  |  |       extract(to: tmp_unpack_dir, basename: basename, verbose: verbose) | 
					
						
							| 
									
										
										
										
											2018-07-16 19:00:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       children = tmp_unpack_dir.children | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-16 20:10:22 +02:00
										 |  |  |       if children.count == 1 && !children.first.directory? | 
					
						
							| 
									
										
										
										
											2018-11-04 17:28:41 +01:00
										 |  |  |         FileUtils.chmod "+rw", children.first, verbose: verbose | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-03 10:32:29 +01:00
										 |  |  |         s = UnpackStrategy.detect(children.first, prioritise_extension: prioritise_extension) | 
					
						
							| 
									
										
										
										
											2018-07-16 19:00:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-03 10:32:29 +01:00
										 |  |  |         s.extract_nestedly(to: to, verbose: verbose, prioritise_extension: prioritise_extension) | 
					
						
							| 
									
										
										
										
											2018-07-16 19:00:49 +02:00
										 |  |  |         next | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  |       Directory.new(tmp_unpack_dir).extract(to: to, verbose: verbose) | 
					
						
							| 
									
										
										
										
											2018-09-29 10:49:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-02 13:33:00 +02:00
										 |  |  |       FileUtils.chmod_R "+w", tmp_unpack_dir, force: true, verbose: verbose | 
					
						
							| 
									
										
										
										
											2018-07-16 19:00:49 +02:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def dependencies | 
					
						
							|  |  |  |     [] | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2018-07-01 23:35:29 +02:00
										 |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  | require "unpack_strategy/air" | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  | require "unpack_strategy/bazaar" | 
					
						
							|  |  |  | require "unpack_strategy/bzip2" | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  | require "unpack_strategy/cab" | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  | require "unpack_strategy/compress" | 
					
						
							|  |  |  | require "unpack_strategy/cvs" | 
					
						
							|  |  |  | require "unpack_strategy/directory" | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  | require "unpack_strategy/dmg" | 
					
						
							|  |  |  | require "unpack_strategy/executable" | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  | require "unpack_strategy/fossil" | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  | require "unpack_strategy/generic_unar" | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  | require "unpack_strategy/git" | 
					
						
							|  |  |  | require "unpack_strategy/gzip" | 
					
						
							|  |  |  | require "unpack_strategy/jar" | 
					
						
							|  |  |  | require "unpack_strategy/lha" | 
					
						
							|  |  |  | require "unpack_strategy/lua_rock" | 
					
						
							|  |  |  | require "unpack_strategy/lzip" | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  | require "unpack_strategy/lzma" | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  | require "unpack_strategy/mercurial" | 
					
						
							|  |  |  | require "unpack_strategy/microsoft_office_xml" | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  | require "unpack_strategy/otf" | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  | require "unpack_strategy/p7zip" | 
					
						
							| 
									
										
										
										
											2018-09-11 19:21:18 +02:00
										 |  |  | require "unpack_strategy/pax" | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  | require "unpack_strategy/pkg" | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  | require "unpack_strategy/rar" | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  | require "unpack_strategy/self_extracting_executable" | 
					
						
							|  |  |  | require "unpack_strategy/sit" | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  | require "unpack_strategy/subversion" | 
					
						
							|  |  |  | require "unpack_strategy/tar" | 
					
						
							| 
									
										
										
										
											2018-07-23 23:04:49 +02:00
										 |  |  | require "unpack_strategy/ttf" | 
					
						
							| 
									
										
										
										
											2018-07-23 20:59:21 +02:00
										 |  |  | require "unpack_strategy/uncompressed" | 
					
						
							|  |  |  | require "unpack_strategy/xar" | 
					
						
							|  |  |  | require "unpack_strategy/xz" | 
					
						
							|  |  |  | require "unpack_strategy/zip" | 
					
						
							| 
									
										
										
										
											2021-09-16 15:56:31 +01:00
										 |  |  | require "unpack_strategy/zstd" |