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.
- checksums.yaml +7 -0
- data/.github/workflows/release.yml +36 -0
- data/.github/workflows/rspec.yml +47 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/Gemfile +14 -0
- data/LICENSE.adoc +13 -0
- data/README.adoc +102 -0
- data/Rakefile +4 -0
- data/excavate.gemspec +34 -0
- data/lib/excavate.rb +12 -0
- data/lib/excavate/archive.rb +96 -0
- data/lib/excavate/extractors.rb +9 -0
- data/lib/excavate/extractors/cab_extractor.rb +33 -0
- data/lib/excavate/extractors/cpio/cpio.rb +199 -0
- data/lib/excavate/extractors/cpio/cpio_old_format.rb +436 -0
- data/lib/excavate/extractors/cpio_extractor.rb +44 -0
- data/lib/excavate/extractors/extractor.rb +13 -0
- data/lib/excavate/extractors/gzip_extractor.rb +13 -0
- data/lib/excavate/extractors/ole_extractor.rb +66 -0
- data/lib/excavate/extractors/rpm_extractor.rb +33 -0
- data/lib/excavate/extractors/seven_zip_extractor.rb +13 -0
- data/lib/excavate/extractors/tar_extractor.rb +29 -0
- data/lib/excavate/extractors/zip_extractor.rb +17 -0
- data/lib/excavate/file_magic.rb +18 -0
- data/lib/excavate/utils.rb +14 -0
- data/lib/excavate/version.rb +5 -0
- metadata +143 -0
@@ -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 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,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
|
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: []
|