excavate 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,44 @@
1
+ require_relative "cpio/cpio"
2
+ require_relative "cpio/cpio_old_format"
3
+
4
+ module Excavate
5
+ module Extractors
6
+ class CpioExtractor < Extractor
7
+ def extract(target)
8
+ extract_cpio_new_format(target)
9
+ rescue RuntimeError => e
10
+ raise unless e.message.start_with?("Invalid magic")
11
+
12
+ extract_cpio_old_format(target)
13
+ end
14
+
15
+ private
16
+
17
+ def extract_cpio_new_format(target)
18
+ File.open(@archive, "rb") do |archive_file|
19
+ CPIO::ASCIIReader.new(archive_file).each do |entry, file|
20
+ path = File.join(target, entry.name)
21
+ if entry.directory?
22
+ FileUtils.mkdir_p(path)
23
+ else
24
+ File.write(path, file.read, mode: "wb")
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def extract_cpio_old_format(target)
31
+ File.open(@archive, "rb") do |archive_file|
32
+ CPIO::ArchiveReader.new(archive_file).each_entry do |entry|
33
+ path = File.expand_path(entry.filename, target)
34
+ if entry.directory?
35
+ FileUtils.mkdir_p(path)
36
+ else
37
+ File.write(path, entry.data, mode: "wb")
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,13 @@
1
+ module Excavate
2
+ module Extractors
3
+ class Extractor
4
+ def initialize(archive)
5
+ @archive = archive
6
+ end
7
+
8
+ def extract(_target)
9
+ raise NotImplementedError.new("You must implement this method")
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Excavate
2
+ module Extractors
3
+ class GzipExtractor < Extractor
4
+ def extract(target)
5
+ Zlib::GzipReader.open(@archive) do |gz|
6
+ basename = File.basename(@archive, ".*")
7
+ path = File.join(target, basename)
8
+ File.write(path, gz.read, mode: "wb")
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,66 @@
1
+ require "ole/storage"
2
+
3
+ module Excavate
4
+ module Extractors
5
+ class OleExtractor < Extractor
6
+ def extract(target)
7
+ do_extract(target)
8
+ rename_archives(target)
9
+ end
10
+
11
+ private
12
+
13
+ def do_extract(target)
14
+ reset_filename_lookup
15
+
16
+ Ole::Storage.open(@archive) do |ole|
17
+ children(ole).each do |file|
18
+ filename = prepare_filename(file)
19
+ path = File.join(target, filename)
20
+ content = ole.file.read(file)
21
+ File.write(path, content, mode: "wb")
22
+ end
23
+ end
24
+ end
25
+
26
+ def children(ole)
27
+ ole.dir.entries(".") - [".", ".."]
28
+ end
29
+
30
+ def reset_filename_lookup
31
+ @file_lookup = {}
32
+ end
33
+
34
+ def prepare_filename(file)
35
+ filename = sanitize_filename(file)
36
+
37
+ @file_lookup[filename] ||= 0
38
+ @file_lookup[filename] += 1
39
+ filename += @file_lookup[filename].to_s if @file_lookup[filename] > 1
40
+
41
+ filename
42
+ end
43
+
44
+ def sanitize_filename(filename)
45
+ filename.strip.tap do |name|
46
+ # NOTE: File.basename doesn't work right with Windows paths on Unix
47
+ # get only the filename, not the whole path
48
+ name.gsub!(/^.*(\\|\/)/, "")
49
+
50
+ # Strip out the non-ascii character
51
+ name.gsub!(/[^0-9A-Za-z.\-]/, "_")
52
+ end
53
+ end
54
+
55
+ def rename_archives(target)
56
+ Dir.glob(File.join(target, "**", "*")).each do |file|
57
+ FileUtils.mv(file, "#{file}.cab") if cab?(file)
58
+ end
59
+ end
60
+
61
+ def cab?(file)
62
+ FileMagic.detect(file) == :cab
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,33 @@
1
+ require "arr-pm"
2
+
3
+ # fix for Ruby 3.0
4
+ unless RPM::File::Header::HEADER_MAGIC == "\x8e\xad\xe8\x01\x00\x00\x00\x00".force_encoding("BINARY")
5
+ RPM::File::Header.send(:remove_const, "HEADER_MAGIC")
6
+ RPM::File::Header.const_set("HEADER_MAGIC", "\x8e\xad\xe8\x01\x00\x00\x00\x00".force_encoding("BINARY"))
7
+ end
8
+
9
+ module Excavate
10
+ module Extractors
11
+ class RpmExtractor < Extractor
12
+ def extract(target)
13
+ File.open(@archive, "rb") do |file|
14
+ rpm = RPM::File.new(file)
15
+ content = rpm.payload.read
16
+ path = target_path(@archive, rpm.tags, target)
17
+
18
+ File.write(path, content, mode: "wb")
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def target_path(archive, tags, dir)
25
+ archive_format = tags[:payloadformat]
26
+ compression_format = tags[:payloadcompressor] == "gzip" ? "gz" : tags[:payloadcompressor]
27
+ basename = File.basename(archive, ".*")
28
+ filename = basename + "." + archive_format + "." + compression_format
29
+ File.join(dir, filename)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ require "seven_zip_ruby"
2
+
3
+ module Excavate
4
+ module Extractors
5
+ class SevenZipExtractor < Extractor
6
+ def extract(target)
7
+ File.open(@archive, "rb") do |file|
8
+ SevenZipRuby::Reader.extract_all(file, target)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ require "rubygems/package"
2
+
3
+ module Excavate
4
+ module Extractors
5
+ class TarExtractor < Extractor
6
+ def extract(target)
7
+ File.open(@archive, "rb") do |archive_file|
8
+ Gem::Package::TarReader.new(archive_file) do |tar|
9
+ tar.each do |tarfile|
10
+ save_tar_file(tarfile, target)
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def save_tar_file(file, dir)
19
+ path = File.join(dir, file.full_name)
20
+
21
+ if file.directory?
22
+ FileUtils.mkdir_p(path)
23
+ else
24
+ File.write(path, file.read, mode: "wb")
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ require "zip"
2
+
3
+ module Excavate
4
+ module Extractors
5
+ class ZipExtractor < Extractor
6
+ def extract(target)
7
+ Zip::File.open(@archive) do |zip_file|
8
+ zip_file.each do |entry|
9
+ path = File.join(target, entry.name)
10
+ FileUtils.mkdir_p(File.dirname(path))
11
+ entry.extract(path)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ module Excavate
2
+ class FileMagic
3
+ def self.detect(path)
4
+ new(path).detect
5
+ end
6
+
7
+ def initialize(path)
8
+ @path = path
9
+ end
10
+
11
+ def detect
12
+ case File.read(@path, 8, mode: "rb")
13
+ when "MSCF\x00\x00\x00\x00".force_encoding("BINARY")
14
+ :cab
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module Excavate
2
+ module Utils
3
+ module_function
4
+
5
+ def silence_stream(stream)
6
+ old_stream = stream.dup
7
+ stream.reopen(RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ ? "NUL:" : "/dev/null") # rubocop:disable Performance/RegexpMatch, Metrics/LineLength
8
+ stream.sync = true
9
+ yield
10
+ ensure
11
+ stream.reopen(old_stream)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Excavate
4
+ VERSION = "0.1.0"
5
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: excavate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ribose Inc.
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-02-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: arr-pm
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: libmspack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ruby-ole
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubyzip
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: seven_zip_ruby
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ description: Extract nested archives with a single command.
84
+ email:
85
+ - open.source@ribose.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".github/workflows/release.yml"
91
+ - ".github/workflows/rspec.yml"
92
+ - ".gitignore"
93
+ - ".rspec"
94
+ - ".rubocop.yml"
95
+ - Gemfile
96
+ - LICENSE.adoc
97
+ - README.adoc
98
+ - Rakefile
99
+ - excavate.gemspec
100
+ - lib/excavate.rb
101
+ - lib/excavate/archive.rb
102
+ - lib/excavate/extractors.rb
103
+ - lib/excavate/extractors/cab_extractor.rb
104
+ - lib/excavate/extractors/cpio/cpio.rb
105
+ - lib/excavate/extractors/cpio/cpio_old_format.rb
106
+ - lib/excavate/extractors/cpio_extractor.rb
107
+ - lib/excavate/extractors/extractor.rb
108
+ - lib/excavate/extractors/gzip_extractor.rb
109
+ - lib/excavate/extractors/ole_extractor.rb
110
+ - lib/excavate/extractors/rpm_extractor.rb
111
+ - lib/excavate/extractors/seven_zip_extractor.rb
112
+ - lib/excavate/extractors/tar_extractor.rb
113
+ - lib/excavate/extractors/zip_extractor.rb
114
+ - lib/excavate/file_magic.rb
115
+ - lib/excavate/utils.rb
116
+ - lib/excavate/version.rb
117
+ homepage: https://github.com/fontist/excavate
118
+ licenses:
119
+ - BSD-3-Clause
120
+ metadata:
121
+ homepage_uri: https://github.com/fontist/excavate
122
+ source_code_uri: https://github.com/fontist/excavate
123
+ changelog_uri: https://github.com/fontist/excavate
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubygems_version: 3.0.3
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Extract nested archives with a single command.
143
+ test_files: []