rom-distillery 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +6 -0
- data/LICENSE +287 -0
- data/README.md +24 -0
- data/bin/rhum +6 -0
- data/distillery.gemspec +38 -0
- data/lib/distillery.rb +10 -0
- data/lib/distillery/archiver.rb +372 -0
- data/lib/distillery/archiver/archive.rb +102 -0
- data/lib/distillery/archiver/external.rb +182 -0
- data/lib/distillery/archiver/external.yaml +31 -0
- data/lib/distillery/archiver/libarchive.rb +105 -0
- data/lib/distillery/archiver/zip.rb +88 -0
- data/lib/distillery/cli.rb +234 -0
- data/lib/distillery/cli/check.rb +100 -0
- data/lib/distillery/cli/clean.rb +60 -0
- data/lib/distillery/cli/header.rb +61 -0
- data/lib/distillery/cli/index.rb +65 -0
- data/lib/distillery/cli/overlap.rb +39 -0
- data/lib/distillery/cli/rebuild.rb +47 -0
- data/lib/distillery/cli/rename.rb +34 -0
- data/lib/distillery/cli/repack.rb +113 -0
- data/lib/distillery/cli/validate.rb +171 -0
- data/lib/distillery/datfile.rb +180 -0
- data/lib/distillery/error.rb +13 -0
- data/lib/distillery/game.rb +70 -0
- data/lib/distillery/game/release.rb +40 -0
- data/lib/distillery/refinements.rb +41 -0
- data/lib/distillery/rom-archive.rb +266 -0
- data/lib/distillery/rom.rb +585 -0
- data/lib/distillery/rom/path.rb +110 -0
- data/lib/distillery/rom/path/archive.rb +103 -0
- data/lib/distillery/rom/path/file.rb +100 -0
- data/lib/distillery/rom/path/virtual.rb +70 -0
- data/lib/distillery/storage.rb +170 -0
- data/lib/distillery/vault.rb +433 -0
- data/lib/distillery/version.rb +7 -0
- metadata +192 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c93dc6ca08201ccc0ba94c522c397149ee26b5ce2419755c5411d008d62df25c
|
4
|
+
data.tar.gz: 3bc0071cf61768f4bfe946f3cb53e07919a81b7f1c73fdd68e102bd62b4705bc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9ccca87474a1cdb94e11f12b1898aa624b7d289880ff11fc732f0ba8cde4324ea899012c96783f820a155139ed433b75388766b975e1ba234f0a9ea5b33eb00f
|
7
|
+
data.tar.gz: 508208b41b94c7e4c1aadb6a132bc43e4a54de063a7ea88e3fe5e39c6541af9479b03c78341bc0d0607739d8db9c99bd891a7523059829152b74ae9600276092
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,287 @@
|
|
1
|
+
EUROPEAN UNION PUBLIC LICENCE v. 1.2
|
2
|
+
EUPL © the European Union 2007, 2016
|
3
|
+
|
4
|
+
This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined
|
5
|
+
below) which is provided under the terms of this Licence. Any use of the Work,
|
6
|
+
other than as authorised under this Licence is prohibited (to the extent such
|
7
|
+
use is covered by a right of the copyright holder of the Work).
|
8
|
+
|
9
|
+
The Work is provided under the terms of this Licence when the Licensor (as
|
10
|
+
defined below) has placed the following notice immediately following the
|
11
|
+
copyright notice for the Work:
|
12
|
+
|
13
|
+
Licensed under the EUPL
|
14
|
+
|
15
|
+
or has expressed by any other means his willingness to license under the EUPL.
|
16
|
+
|
17
|
+
1. Definitions
|
18
|
+
|
19
|
+
In this Licence, the following terms have the following meaning:
|
20
|
+
|
21
|
+
- ‘The Licence’: this Licence.
|
22
|
+
|
23
|
+
- ‘The Original Work’: the work or software distributed or communicated by the
|
24
|
+
Licensor under this Licence, available as Source Code and also as Executable
|
25
|
+
Code as the case may be.
|
26
|
+
|
27
|
+
- ‘Derivative Works’: the works or software that could be created by the
|
28
|
+
Licensee, based upon the Original Work or modifications thereof. This Licence
|
29
|
+
does not define the extent of modification or dependence on the Original Work
|
30
|
+
required in order to classify a work as a Derivative Work; this extent is
|
31
|
+
determined by copyright law applicable in the country mentioned in Article 15.
|
32
|
+
|
33
|
+
- ‘The Work’: the Original Work or its Derivative Works.
|
34
|
+
|
35
|
+
- ‘The Source Code’: the human-readable form of the Work which is the most
|
36
|
+
convenient for people to study and modify.
|
37
|
+
|
38
|
+
- ‘The Executable Code’: any code which has generally been compiled and which is
|
39
|
+
meant to be interpreted by a computer as a program.
|
40
|
+
|
41
|
+
- ‘The Licensor’: the natural or legal person that distributes or communicates
|
42
|
+
the Work under the Licence.
|
43
|
+
|
44
|
+
- ‘Contributor(s)’: any natural or legal person who modifies the Work under the
|
45
|
+
Licence, or otherwise contributes to the creation of a Derivative Work.
|
46
|
+
|
47
|
+
- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
|
48
|
+
the Work under the terms of the Licence.
|
49
|
+
|
50
|
+
- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
|
51
|
+
renting, distributing, communicating, transmitting, or otherwise making
|
52
|
+
available, online or offline, copies of the Work or providing access to its
|
53
|
+
essential functionalities at the disposal of any other natural or legal
|
54
|
+
person.
|
55
|
+
|
56
|
+
2. Scope of the rights granted by the Licence
|
57
|
+
|
58
|
+
The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
|
59
|
+
sublicensable licence to do the following, for the duration of copyright vested
|
60
|
+
in the Original Work:
|
61
|
+
|
62
|
+
- use the Work in any circumstance and for all usage,
|
63
|
+
- reproduce the Work,
|
64
|
+
- modify the Work, and make Derivative Works based upon the Work,
|
65
|
+
- communicate to the public, including the right to make available or display
|
66
|
+
the Work or copies thereof to the public and perform publicly, as the case may
|
67
|
+
be, the Work,
|
68
|
+
- distribute the Work or copies thereof,
|
69
|
+
- lend and rent the Work or copies thereof,
|
70
|
+
- sublicense rights in the Work or copies thereof.
|
71
|
+
|
72
|
+
Those rights can be exercised on any media, supports and formats, whether now
|
73
|
+
known or later invented, as far as the applicable law permits so.
|
74
|
+
|
75
|
+
In the countries where moral rights apply, the Licensor waives his right to
|
76
|
+
exercise his moral right to the extent allowed by law in order to make effective
|
77
|
+
the licence of the economic rights here above listed.
|
78
|
+
|
79
|
+
The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to
|
80
|
+
any patents held by the Licensor, to the extent necessary to make use of the
|
81
|
+
rights granted on the Work under this Licence.
|
82
|
+
|
83
|
+
3. Communication of the Source Code
|
84
|
+
|
85
|
+
The Licensor may provide the Work either in its Source Code form, or as
|
86
|
+
Executable Code. If the Work is provided as Executable Code, the Licensor
|
87
|
+
provides in addition a machine-readable copy of the Source Code of the Work
|
88
|
+
along with each copy of the Work that the Licensor distributes or indicates, in
|
89
|
+
a notice following the copyright notice attached to the Work, a repository where
|
90
|
+
the Source Code is easily and freely accessible for as long as the Licensor
|
91
|
+
continues to distribute or communicate the Work.
|
92
|
+
|
93
|
+
4. Limitations on copyright
|
94
|
+
|
95
|
+
Nothing in this Licence is intended to deprive the Licensee of the benefits from
|
96
|
+
any exception or limitation to the exclusive rights of the rights owners in the
|
97
|
+
Work, of the exhaustion of those rights or of other applicable limitations
|
98
|
+
thereto.
|
99
|
+
|
100
|
+
5. Obligations of the Licensee
|
101
|
+
|
102
|
+
The grant of the rights mentioned above is subject to some restrictions and
|
103
|
+
obligations imposed on the Licensee. Those obligations are the following:
|
104
|
+
|
105
|
+
Attribution right: The Licensee shall keep intact all copyright, patent or
|
106
|
+
trademarks notices and all notices that refer to the Licence and to the
|
107
|
+
disclaimer of warranties. The Licensee must include a copy of such notices and a
|
108
|
+
copy of the Licence with every copy of the Work he/she distributes or
|
109
|
+
communicates. The Licensee must cause any Derivative Work to carry prominent
|
110
|
+
notices stating that the Work has been modified and the date of modification.
|
111
|
+
|
112
|
+
Copyleft clause: If the Licensee distributes or communicates copies of the
|
113
|
+
Original Works or Derivative Works, this Distribution or Communication will be
|
114
|
+
done under the terms of this Licence or of a later version of this Licence
|
115
|
+
unless the Original Work is expressly distributed only under this version of the
|
116
|
+
Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
|
117
|
+
(becoming Licensor) cannot offer or impose any additional terms or conditions on
|
118
|
+
the Work or Derivative Work that alter or restrict the terms of the Licence.
|
119
|
+
|
120
|
+
Compatibility clause: If the Licensee Distributes or Communicates Derivative
|
121
|
+
Works or copies thereof based upon both the Work and another work licensed under
|
122
|
+
a Compatible Licence, this Distribution or Communication can be done under the
|
123
|
+
terms of this Compatible Licence. For the sake of this clause, ‘Compatible
|
124
|
+
Licence’ refers to the licences listed in the appendix attached to this Licence.
|
125
|
+
Should the Licensee's obligations under the Compatible Licence conflict with
|
126
|
+
his/her obligations under this Licence, the obligations of the Compatible
|
127
|
+
Licence shall prevail.
|
128
|
+
|
129
|
+
Provision of Source Code: When distributing or communicating copies of the Work,
|
130
|
+
the Licensee will provide a machine-readable copy of the Source Code or indicate
|
131
|
+
a repository where this Source will be easily and freely available for as long
|
132
|
+
as the Licensee continues to distribute or communicate the Work.
|
133
|
+
|
134
|
+
Legal Protection: This Licence does not grant permission to use the trade names,
|
135
|
+
trademarks, service marks, or names of the Licensor, except as required for
|
136
|
+
reasonable and customary use in describing the origin of the Work and
|
137
|
+
reproducing the content of the copyright notice.
|
138
|
+
|
139
|
+
6. Chain of Authorship
|
140
|
+
|
141
|
+
The original Licensor warrants that the copyright in the Original Work granted
|
142
|
+
hereunder is owned by him/her or licensed to him/her and that he/she has the
|
143
|
+
power and authority to grant the Licence.
|
144
|
+
|
145
|
+
Each Contributor warrants that the copyright in the modifications he/she brings
|
146
|
+
to the Work are owned by him/her or licensed to him/her and that he/she has the
|
147
|
+
power and authority to grant the Licence.
|
148
|
+
|
149
|
+
Each time You accept the Licence, the original Licensor and subsequent
|
150
|
+
Contributors grant You a licence to their contributions to the Work, under the
|
151
|
+
terms of this Licence.
|
152
|
+
|
153
|
+
7. Disclaimer of Warranty
|
154
|
+
|
155
|
+
The Work is a work in progress, which is continuously improved by numerous
|
156
|
+
Contributors. It is not a finished work and may therefore contain defects or
|
157
|
+
‘bugs’ inherent to this type of development.
|
158
|
+
|
159
|
+
For the above reason, the Work is provided under the Licence on an ‘as is’ basis
|
160
|
+
and without warranties of any kind concerning the Work, including without
|
161
|
+
limitation merchantability, fitness for a particular purpose, absence of defects
|
162
|
+
or errors, accuracy, non-infringement of intellectual property rights other than
|
163
|
+
copyright as stated in Article 6 of this Licence.
|
164
|
+
|
165
|
+
This disclaimer of warranty is an essential part of the Licence and a condition
|
166
|
+
for the grant of any rights to the Work.
|
167
|
+
|
168
|
+
8. Disclaimer of Liability
|
169
|
+
|
170
|
+
Except in the cases of wilful misconduct or damages directly caused to natural
|
171
|
+
persons, the Licensor will in no event be liable for any direct or indirect,
|
172
|
+
material or moral, damages of any kind, arising out of the Licence or of the use
|
173
|
+
of the Work, including without limitation, damages for loss of goodwill, work
|
174
|
+
stoppage, computer failure or malfunction, loss of data or any commercial
|
175
|
+
damage, even if the Licensor has been advised of the possibility of such damage.
|
176
|
+
However, the Licensor will be liable under statutory product liability laws as
|
177
|
+
far such laws apply to the Work.
|
178
|
+
|
179
|
+
9. Additional agreements
|
180
|
+
|
181
|
+
While distributing the Work, You may choose to conclude an additional agreement,
|
182
|
+
defining obligations or services consistent with this Licence. However, if
|
183
|
+
accepting obligations, You may act only on your own behalf and on your sole
|
184
|
+
responsibility, not on behalf of the original Licensor or any other Contributor,
|
185
|
+
and only if You agree to indemnify, defend, and hold each Contributor harmless
|
186
|
+
for any liability incurred by, or claims asserted against such Contributor by
|
187
|
+
the fact You have accepted any warranty or additional liability.
|
188
|
+
|
189
|
+
10. Acceptance of the Licence
|
190
|
+
|
191
|
+
The provisions of this Licence can be accepted by clicking on an icon ‘I agree’
|
192
|
+
placed under the bottom of a window displaying the text of this Licence or by
|
193
|
+
affirming consent in any other similar way, in accordance with the rules of
|
194
|
+
applicable law. Clicking on that icon indicates your clear and irrevocable
|
195
|
+
acceptance of this Licence and all of its terms and conditions.
|
196
|
+
|
197
|
+
Similarly, you irrevocably accept this Licence and all of its terms and
|
198
|
+
conditions by exercising any rights granted to You by Article 2 of this Licence,
|
199
|
+
such as the use of the Work, the creation by You of a Derivative Work or the
|
200
|
+
Distribution or Communication by You of the Work or copies thereof.
|
201
|
+
|
202
|
+
11. Information to the public
|
203
|
+
|
204
|
+
In case of any Distribution or Communication of the Work by means of electronic
|
205
|
+
communication by You (for example, by offering to download the Work from a
|
206
|
+
remote location) the distribution channel or media (for example, a website) must
|
207
|
+
at least provide to the public the information requested by the applicable law
|
208
|
+
regarding the Licensor, the Licence and the way it may be accessible, concluded,
|
209
|
+
stored and reproduced by the Licensee.
|
210
|
+
|
211
|
+
12. Termination of the Licence
|
212
|
+
|
213
|
+
The Licence and the rights granted hereunder will terminate automatically upon
|
214
|
+
any breach by the Licensee of the terms of the Licence.
|
215
|
+
|
216
|
+
Such a termination will not terminate the licences of any person who has
|
217
|
+
received the Work from the Licensee under the Licence, provided such persons
|
218
|
+
remain in full compliance with the Licence.
|
219
|
+
|
220
|
+
13. Miscellaneous
|
221
|
+
|
222
|
+
Without prejudice of Article 9 above, the Licence represents the complete
|
223
|
+
agreement between the Parties as to the Work.
|
224
|
+
|
225
|
+
If any provision of the Licence is invalid or unenforceable under applicable
|
226
|
+
law, this will not affect the validity or enforceability of the Licence as a
|
227
|
+
whole. Such provision will be construed or reformed so as necessary to make it
|
228
|
+
valid and enforceable.
|
229
|
+
|
230
|
+
The European Commission may publish other linguistic versions or new versions of
|
231
|
+
this Licence or updated versions of the Appendix, so far this is required and
|
232
|
+
reasonable, without reducing the scope of the rights granted by the Licence. New
|
233
|
+
versions of the Licence will be published with a unique version number.
|
234
|
+
|
235
|
+
All linguistic versions of this Licence, approved by the European Commission,
|
236
|
+
have identical value. Parties can take advantage of the linguistic version of
|
237
|
+
their choice.
|
238
|
+
|
239
|
+
14. Jurisdiction
|
240
|
+
|
241
|
+
Without prejudice to specific agreement between parties,
|
242
|
+
|
243
|
+
- any litigation resulting from the interpretation of this License, arising
|
244
|
+
between the European Union institutions, bodies, offices or agencies, as a
|
245
|
+
Licensor, and any Licensee, will be subject to the jurisdiction of the Court
|
246
|
+
of Justice of the European Union, as laid down in article 272 of the Treaty on
|
247
|
+
the Functioning of the European Union,
|
248
|
+
|
249
|
+
- any litigation arising between other parties and resulting from the
|
250
|
+
interpretation of this License, will be subject to the exclusive jurisdiction
|
251
|
+
of the competent court where the Licensor resides or conducts its primary
|
252
|
+
business.
|
253
|
+
|
254
|
+
15. Applicable Law
|
255
|
+
|
256
|
+
Without prejudice to specific agreement between parties,
|
257
|
+
|
258
|
+
- this Licence shall be governed by the law of the European Union Member State
|
259
|
+
where the Licensor has his seat, resides or has his registered office,
|
260
|
+
|
261
|
+
- this licence shall be governed by Belgian law if the Licensor has no seat,
|
262
|
+
residence or registered office inside a European Union Member State.
|
263
|
+
|
264
|
+
Appendix
|
265
|
+
|
266
|
+
‘Compatible Licences’ according to Article 5 EUPL are:
|
267
|
+
|
268
|
+
- GNU General Public License (GPL) v. 2, v. 3
|
269
|
+
- GNU Affero General Public License (AGPL) v. 3
|
270
|
+
- Open Software License (OSL) v. 2.1, v. 3.0
|
271
|
+
- Eclipse Public License (EPL) v. 1.0
|
272
|
+
- CeCILL v. 2.0, v. 2.1
|
273
|
+
- Mozilla Public Licence (MPL) v. 2
|
274
|
+
- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
|
275
|
+
- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
|
276
|
+
works other than software
|
277
|
+
- European Union Public Licence (EUPL) v. 1.1, v. 1.2
|
278
|
+
- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong
|
279
|
+
Reciprocity (LiLiQ-R+).
|
280
|
+
|
281
|
+
The European Commission may update this Appendix to later versions of the above
|
282
|
+
licences without producing a new version of the EUPL, as long as they provide
|
283
|
+
the rights granted in Article 2 of this Licence and protect the covered Source
|
284
|
+
Code from exclusive appropriation.
|
285
|
+
|
286
|
+
All other changes or additions to this Appendix require the production of a new
|
287
|
+
EUPL version.
|
data/README.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Requirements
|
2
|
+
============
|
3
|
+
* The 7z, zip, unzip programs
|
4
|
+
|
5
|
+
|
6
|
+
Usage
|
7
|
+
=====
|
8
|
+
|
9
|
+
~~~sh
|
10
|
+
# Get help
|
11
|
+
rhum --help
|
12
|
+
|
13
|
+
# Validat ROMs against DAT file
|
14
|
+
rhum -D ${datfile} validate ${rom_directory}
|
15
|
+
|
16
|
+
# Repack archive using 7z format
|
17
|
+
rhum repack -F 7z ${rom_directory}
|
18
|
+
|
19
|
+
# Generate checksum index
|
20
|
+
rhum index ${rom_directory}
|
21
|
+
|
22
|
+
# Save ROM header to the specified directory
|
23
|
+
rhum -D ${header_dir} header ${rom_directory}
|
24
|
+
~~~
|
data/bin/rhum
ADDED
data/distillery.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.unshift File.expand_path("../lib", __FILE__)
|
3
|
+
require "distillery/version"
|
4
|
+
|
5
|
+
# NOTE: 'distillery' name is taken but not used since 2012
|
6
|
+
# https://rubygems.org/gems/distillery
|
7
|
+
|
8
|
+
Gem::Specification.new do |s|
|
9
|
+
s.name = "rom-distillery"
|
10
|
+
s.version = Distillery::VERSION
|
11
|
+
s.platform = Gem::Platform::RUBY
|
12
|
+
s.licenses = [ 'EUPL-1.2' ]
|
13
|
+
s.summary = "ROM manager"
|
14
|
+
s.description = "Help organise emulation ROM using DAT file"
|
15
|
+
|
16
|
+
s.required_ruby_version = '>= 2.5'
|
17
|
+
|
18
|
+
s.authors = ["Stephane D'Alu"]
|
19
|
+
s.email = ["sdalu@sdalu.com"]
|
20
|
+
s.homepage = "http://github.com/sdalu/distillery"
|
21
|
+
|
22
|
+
s.add_dependency 'nokogiri'
|
23
|
+
s.add_dependency 'rubyzip'
|
24
|
+
s.add_dependency 'tty-screen'
|
25
|
+
s.add_dependency 'tty-logger'
|
26
|
+
s.add_dependency 'tty-spinner'
|
27
|
+
s.add_dependency 'tty-progressbar'
|
28
|
+
|
29
|
+
s.add_development_dependency "yard"
|
30
|
+
s.add_development_dependency "rake"
|
31
|
+
|
32
|
+
s.executables = [ 'rhum' ]
|
33
|
+
s.files = %w[ LICENSE README.md Gemfile distillery.gemspec ] +
|
34
|
+
Dir['lib/**/*.rb' ] +
|
35
|
+
Dir['lib/**/*.yaml']
|
36
|
+
|
37
|
+
end
|
38
|
+
|
data/lib/distillery.rb
ADDED
@@ -0,0 +1,372 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# SPDX-License-Identifier: EUPL-1.2
|
3
|
+
|
4
|
+
require 'set'
|
5
|
+
|
6
|
+
require_relative 'archiver/archive'
|
7
|
+
|
8
|
+
module Distillery
|
9
|
+
|
10
|
+
|
11
|
+
# @abstract
|
12
|
+
# Allow processing of archives
|
13
|
+
#
|
14
|
+
class Archiver
|
15
|
+
include Enumerable
|
16
|
+
|
17
|
+
# Standard error for Archiver class and subclasses
|
18
|
+
class Error < StandardError
|
19
|
+
end
|
20
|
+
|
21
|
+
# Notification of not archiver found
|
22
|
+
class ArchiverNotFound < Error
|
23
|
+
end
|
24
|
+
|
25
|
+
# Excution error for external process
|
26
|
+
class ExecError < Error
|
27
|
+
end
|
28
|
+
|
29
|
+
# Processing error when dealing with archive
|
30
|
+
class ProcessingError < Error
|
31
|
+
end
|
32
|
+
|
33
|
+
# InputStream used by Archiver#reader
|
34
|
+
class InputStream
|
35
|
+
def initialize(io)
|
36
|
+
@io = io
|
37
|
+
end
|
38
|
+
|
39
|
+
# Read data
|
40
|
+
#
|
41
|
+
# @param length [Integer, nil] number of bytes to read,
|
42
|
+
# whole data if nil
|
43
|
+
#
|
44
|
+
# @return [String, nil] data or nil if end of stream
|
45
|
+
#
|
46
|
+
def read(length=nil)
|
47
|
+
@io.read(length)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# OutputStream used by Archiver#writer
|
52
|
+
class OutputStream
|
53
|
+
def initialize(io)
|
54
|
+
@io = io
|
55
|
+
end
|
56
|
+
|
57
|
+
# Write data
|
58
|
+
#
|
59
|
+
# @param data [String] date to write
|
60
|
+
#
|
61
|
+
# @return [Integer] number of bytes written
|
62
|
+
#
|
63
|
+
def write(data)
|
64
|
+
@io.write(data)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# @!visibility private
|
70
|
+
@@logger = nil
|
71
|
+
|
72
|
+
# @!visibility private
|
73
|
+
@@providers = []
|
74
|
+
|
75
|
+
# @!visibility private
|
76
|
+
@@archivers = Set.new
|
77
|
+
|
78
|
+
# @!visibility private
|
79
|
+
@@mimetypes = {}
|
80
|
+
|
81
|
+
# @!visibility private
|
82
|
+
@@extensions = {}
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
# Register a logger
|
87
|
+
#
|
88
|
+
# @param logger [Logger,nil] logger
|
89
|
+
#
|
90
|
+
# @return logger
|
91
|
+
#
|
92
|
+
def self.logger=(logger)
|
93
|
+
@@logger = logger
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# Get the regisered logger
|
98
|
+
#
|
99
|
+
# @return [Logger,nil]
|
100
|
+
#
|
101
|
+
def self.logger
|
102
|
+
@@logger
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
# Add an archiver provider class
|
107
|
+
#
|
108
|
+
# @param provider [Class] archiver provider
|
109
|
+
#
|
110
|
+
# @return [self]
|
111
|
+
#
|
112
|
+
def self.add(provider)
|
113
|
+
@@providers << provider
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
# List of archivers' providers in loading order.
|
119
|
+
#
|
120
|
+
# @return [Array<Class>] Archiver class
|
121
|
+
#
|
122
|
+
def self.providers
|
123
|
+
# Could be done by looking at constants
|
124
|
+
# constants.lazy.map {|c| const_get(c) }.select {|k| k < self }.to_a
|
125
|
+
# But we want to keep loading order
|
126
|
+
@@providers
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
# Perform automatic registration of all the archive providers
|
131
|
+
#
|
132
|
+
# @return [self]
|
133
|
+
#
|
134
|
+
def self.registering
|
135
|
+
self.providers.each do |p|
|
136
|
+
p.registering
|
137
|
+
end
|
138
|
+
self
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
# Register an archiver.
|
144
|
+
#
|
145
|
+
# @param [Archiver] archiver Archiver to register
|
146
|
+
# @param [Boolean] warnings Emit warning when overriding
|
147
|
+
#
|
148
|
+
def self.register(archiver, warnings: true)
|
149
|
+
# Notifier
|
150
|
+
notify = if warnings
|
151
|
+
->(type, key, old, new) {
|
152
|
+
oname = old.class.name.split('::').last
|
153
|
+
nname = new.class.name.split('::').last
|
154
|
+
Archiver.logger&.warn {
|
155
|
+
"#{self} overriding #{type} for #{key}" \
|
156
|
+
" [#{oname} -> #{nname}]"
|
157
|
+
}
|
158
|
+
}
|
159
|
+
end
|
160
|
+
|
161
|
+
# Add archiver
|
162
|
+
@@archivers.add(archiver)
|
163
|
+
|
164
|
+
# Register mimetypes
|
165
|
+
Array(archiver.mimetypes).each {|mt|
|
166
|
+
@@mimetypes.merge!(mt => archiver) {|key, old, new|
|
167
|
+
notify&.call("mimetype", key, old, new)
|
168
|
+
new
|
169
|
+
}
|
170
|
+
}
|
171
|
+
# Register extensions
|
172
|
+
Array(archiver.extensions).each {|ext|
|
173
|
+
@@extensions.merge!(ext.downcase => archiver) {|key, old, new|
|
174
|
+
notify&.call("extension", key, old, new)
|
175
|
+
new
|
176
|
+
}
|
177
|
+
}
|
178
|
+
# Return archiver
|
179
|
+
archiver
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
# List of registered archivers
|
184
|
+
#
|
185
|
+
# @return [Array<Archiver>]
|
186
|
+
#
|
187
|
+
def self.archivers
|
188
|
+
@@archivers.to_a
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
# Archiver able to process the selected mimetype
|
193
|
+
#
|
194
|
+
def self.for_mimetype(mimetype)
|
195
|
+
@@mimetypes[mimetype]
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
# Archiver able to process the selected extension
|
200
|
+
#
|
201
|
+
def self.for_extension(extension)
|
202
|
+
extension = extension[1..-1] if extension[0] == '.'
|
203
|
+
@@extensions[extension.downcase]
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
# Archiver able to process the selected file.
|
208
|
+
#
|
209
|
+
# @param [String] file archive file tpo consider
|
210
|
+
#
|
211
|
+
# @return [Archiver] archiver to use for processing file
|
212
|
+
# @return [nil] no matching archiver found
|
213
|
+
#
|
214
|
+
def self.for_file(file)
|
215
|
+
# Find by extension
|
216
|
+
parts = File.basename(file).split('.')
|
217
|
+
extlist = 1.upto(parts.size-1).map {|i| parts[i..-1].join('.') }
|
218
|
+
archiver = extlist.lazy.map {|ext| self.for_extension(ext) }
|
219
|
+
.find {|arc| ! arc.nil? }
|
220
|
+
|
221
|
+
# Find by mimetype if previously failed
|
222
|
+
archiver ||= if defined?(MimeMagic)
|
223
|
+
begin
|
224
|
+
File.open(file) {|io|
|
225
|
+
self.for_mimetype(MimeMagic.by_magic(io))
|
226
|
+
}
|
227
|
+
rescue Errno::ENOENT
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
# Return found archiver (or nil)
|
232
|
+
archiver
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
# Return an archive instance of the specified file, or invokes the block
|
237
|
+
# with the archive instance passed as parameter.
|
238
|
+
#
|
239
|
+
# @overload for(file)
|
240
|
+
# @param file [String] archive file
|
241
|
+
#
|
242
|
+
# @raise [ArchiverNotFound] an archiver able to process this file
|
243
|
+
# has not been found
|
244
|
+
#
|
245
|
+
# @return [Archive] archive instance
|
246
|
+
#
|
247
|
+
# @overload for(file)
|
248
|
+
# @param file [String] archive file
|
249
|
+
#
|
250
|
+
# @yieldparam archive [Archive] archive instance
|
251
|
+
#
|
252
|
+
# @raise [ArchiverNotFound] an archiver able to process this file
|
253
|
+
# has not been found
|
254
|
+
#
|
255
|
+
# @return [self]
|
256
|
+
#
|
257
|
+
def self.for(file)
|
258
|
+
archive = Archive.new(file)
|
259
|
+
if block_given?
|
260
|
+
yield(archive)
|
261
|
+
self
|
262
|
+
else
|
263
|
+
archive
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
|
269
|
+
|
270
|
+
|
271
|
+
def initialize
|
272
|
+
raise "abstract class"
|
273
|
+
end
|
274
|
+
|
275
|
+
|
276
|
+
# List of supported extensions
|
277
|
+
#
|
278
|
+
# @return [Array<String>]
|
279
|
+
#
|
280
|
+
def extensions
|
281
|
+
[ 'zip' ]
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
# List of supported mimetypes
|
286
|
+
#
|
287
|
+
# @return [Array<String>]
|
288
|
+
#
|
289
|
+
def mimetypes
|
290
|
+
[ 'application/zip' ]
|
291
|
+
end
|
292
|
+
|
293
|
+
|
294
|
+
# Iterate over each archive entry
|
295
|
+
#
|
296
|
+
# @param file [String] archive file
|
297
|
+
#
|
298
|
+
# @yieldparam entry [String]
|
299
|
+
# @yieldparam io [InputStream]
|
300
|
+
#
|
301
|
+
# @return [self,Enumerator]
|
302
|
+
#
|
303
|
+
def each(file, &block)
|
304
|
+
raise "abstract method"
|
305
|
+
end
|
306
|
+
|
307
|
+
|
308
|
+
# Check if the archive contains no entry
|
309
|
+
#
|
310
|
+
# @param file [String] archive file
|
311
|
+
#
|
312
|
+
# @return [Boolean]
|
313
|
+
#
|
314
|
+
def empty?(file)
|
315
|
+
! each(file).any?
|
316
|
+
end
|
317
|
+
|
318
|
+
|
319
|
+
# List archive entries
|
320
|
+
#
|
321
|
+
# @param file [String] archive file
|
322
|
+
#
|
323
|
+
# @return [Array<String>]
|
324
|
+
#
|
325
|
+
def entries(file)
|
326
|
+
each(file).map {|a_entry, _| a_entry }
|
327
|
+
end
|
328
|
+
|
329
|
+
|
330
|
+
# Allow to perform read operation on an archive entry
|
331
|
+
#
|
332
|
+
# @param file [String] archive file
|
333
|
+
# @param entry [String] entry name
|
334
|
+
#
|
335
|
+
# @yieldparam io [InputStream] input stream for reading
|
336
|
+
#
|
337
|
+
# @return block value
|
338
|
+
#
|
339
|
+
def reader(file, entry, &block)
|
340
|
+
each(file) {|a_entry, a_io|
|
341
|
+
next unless a_entry == entry
|
342
|
+
return block.call(a_io)
|
343
|
+
}
|
344
|
+
end
|
345
|
+
|
346
|
+
|
347
|
+
# Allow to perform write operation on an archive entry
|
348
|
+
#
|
349
|
+
# @param file [String] archive file
|
350
|
+
# @param entry [String] entry name
|
351
|
+
#
|
352
|
+
# @yieldparam io [OutputStream] output stream for writing
|
353
|
+
#
|
354
|
+
# @return block value
|
355
|
+
#
|
356
|
+
def writer(file, entry, &block)
|
357
|
+
nil
|
358
|
+
end
|
359
|
+
|
360
|
+
|
361
|
+
# Delete the entry from the archive
|
362
|
+
#
|
363
|
+
# @param file [String] archive file
|
364
|
+
# @param entry [String] entry name
|
365
|
+
#
|
366
|
+
# @return [Boolean] operation status
|
367
|
+
#
|
368
|
+
def delete!(file, entry)
|
369
|
+
false
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|