rom-distillery 0.1
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/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
@@ -0,0 +1,433 @@
|
|
1
|
+
# SPDX-License-Identifier: EUPL-1.2
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
require 'pathname'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'find'
|
7
|
+
|
8
|
+
require_relative 'rom'
|
9
|
+
require_relative 'rom-archive'
|
10
|
+
|
11
|
+
module Distillery
|
12
|
+
|
13
|
+
class Vault
|
14
|
+
include Enumerable
|
15
|
+
|
16
|
+
# @!visibility private
|
17
|
+
GLOB_PATTERN_REGEX = /(?<!\\)[?*}{\[\]]/
|
18
|
+
|
19
|
+
# List of ROM checksums
|
20
|
+
CHECKSUMS = ROM::CHECKSUMS
|
21
|
+
|
22
|
+
# List of archives extensions
|
23
|
+
ARCHIVES = ROMArchive::EXTENSIONS
|
24
|
+
|
25
|
+
# List of files to be ignored
|
26
|
+
IGNORE_FILES = Set[ '.dat', '.missing', '.baddump', '.extra' ]
|
27
|
+
|
28
|
+
# List of directories to be ignored
|
29
|
+
IGNORE_DIRS = Set[ '.roms', '.games', '.trash' ]
|
30
|
+
|
31
|
+
# Directory pruning
|
32
|
+
DIR_PRUNING = Set[ '.dat' ]
|
33
|
+
|
34
|
+
|
35
|
+
# Potential ROM from directory.
|
36
|
+
# @note file in {IGNORE_FILES}, directory in {IGNORE_DIRS},
|
37
|
+
# directories holding a {DIR_PRUNING} file or starting with a
|
38
|
+
# dot are ignored
|
39
|
+
#
|
40
|
+
# @param dir [String] path to directory
|
41
|
+
# @param depth [Integer,nil] exploration depth
|
42
|
+
#
|
43
|
+
# @yieldparam file [String] file being processed
|
44
|
+
# @yieldparam dir: [String] directory relative to
|
45
|
+
#
|
46
|
+
def self.from_dir(dir, depth: nil)
|
47
|
+
Find.find(dir) do |path|
|
48
|
+
basename = File.basename(path)
|
49
|
+
subpath = Pathname(path).relative_path_from(dir).to_s
|
50
|
+
if FileTest.directory?(path)
|
51
|
+
next if path == dir
|
52
|
+
Find.prune if IGNORE_DIRS.include?(basename)
|
53
|
+
Find.prune if basename.start_with?('.')
|
54
|
+
Find.prune if !depth.nil? &&
|
55
|
+
subpath.split(File::Separator).size > depth
|
56
|
+
Find.prune if DIR_PRUNING.any? {|f| File.exists?(f) }
|
57
|
+
elsif FileTest.file?(path)
|
58
|
+
next if IGNORE_FILES.include?(basename)
|
59
|
+
yield(subpath, dir: dir) if block_given?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# Potential ROM from glob
|
66
|
+
# @note file in {IGNORE_FILES}, directory in {IGNORE_DIRS},
|
67
|
+
# directories holding a {DIR_PRUNING} file or starting with a
|
68
|
+
# dot are ignored
|
69
|
+
#
|
70
|
+
# @param glob [String] ruby glob
|
71
|
+
# @param basedir [:guess,nil] basedir to use when interpreting glob
|
72
|
+
# matching
|
73
|
+
#
|
74
|
+
# @yieldparam file [String] file being processed
|
75
|
+
# @yieldparam dir: [String] directory relative to
|
76
|
+
#
|
77
|
+
def self.from_glob(glob, basedir: :guess)
|
78
|
+
if basedir == :guess
|
79
|
+
gentry = glob.split(File::SEPARATOR)
|
80
|
+
idx = gentry.find_index{|entry| entry =~ GLOB_PATTERN_REGEX }
|
81
|
+
gentry = gentry[0,idx]
|
82
|
+
basedir = if gentry.empty? then nil
|
83
|
+
elsif gentry.first.empty? then '/'
|
84
|
+
else File.join(gentry)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Build file list (reject ignored files and dirs)
|
89
|
+
lst = Dir[glob].reject {|path|
|
90
|
+
(! FileTest.file?(path)) ||
|
91
|
+
IGNORE_FILES.include?(File.basename(path)) ||
|
92
|
+
path.split(File::SEPARATOR)[0..-1].any? {|dir|
|
93
|
+
IGNORE_DIRS.include?(dir) || dir.start_with?('.')
|
94
|
+
}
|
95
|
+
}
|
96
|
+
# Build cut list based on directory prunning
|
97
|
+
cutlst = lst.map {|f| File.dirname(f) }.uniq.select {|f|
|
98
|
+
DIR_PRUNING.any? {|p| FileTest.exist?(File.join(f,p)) }
|
99
|
+
}
|
100
|
+
# Apply cut list
|
101
|
+
lst.reject! {|path|
|
102
|
+
cutlst.any? {|cut| path.start_with?("#{cut}#{File::SEPARATOR}") }
|
103
|
+
}
|
104
|
+
|
105
|
+
# Iterate on list
|
106
|
+
lst.each do |path|
|
107
|
+
subpath = if basedir.nil?
|
108
|
+
then path
|
109
|
+
else Pathname(path).relative_path_from(basedir).to_s
|
110
|
+
end
|
111
|
+
yield(subpath, dir: basedir) if block_given?
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def initialize(roms = [])
|
117
|
+
@cksum = Hash[CHECKSUMS.map {|k| [ k, {} ] }]
|
118
|
+
@roms = []
|
119
|
+
|
120
|
+
Array(roms).each {|rom| add_rom(rom) }
|
121
|
+
end
|
122
|
+
|
123
|
+
# @return [Boolean]
|
124
|
+
def empty?
|
125
|
+
@roms.empty?
|
126
|
+
end
|
127
|
+
|
128
|
+
# @return [Integer]
|
129
|
+
def size
|
130
|
+
@roms.size
|
131
|
+
end
|
132
|
+
|
133
|
+
# Iterate over each ROM
|
134
|
+
#
|
135
|
+
# @yieldparam rom [ROM]
|
136
|
+
#
|
137
|
+
# @return [self,Enumerator]
|
138
|
+
#
|
139
|
+
def each
|
140
|
+
block_given? ? @roms.each {|r| yield(r) }
|
141
|
+
: @roms.each
|
142
|
+
end
|
143
|
+
|
144
|
+
# Construct a new ROM vault as the intersection
|
145
|
+
#
|
146
|
+
# @param o [Vault] ROM vault to intersect with self
|
147
|
+
#
|
148
|
+
# @return [Vault]
|
149
|
+
def &(o)
|
150
|
+
Vault::new(@roms.select {|rom| o.match(rom) })
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
# Constuct a new ROM vault as the difference
|
155
|
+
#
|
156
|
+
# @param o [Vault] ROM vault to substract to self
|
157
|
+
#
|
158
|
+
# @return [Vault]
|
159
|
+
def -(o)
|
160
|
+
Vault::new(@roms.reject {|rom| o.match(rom) })
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
# Add ROM
|
165
|
+
#
|
166
|
+
# @param [ROM] *roms ROM to add
|
167
|
+
#
|
168
|
+
# @return self
|
169
|
+
#
|
170
|
+
def <<(rom)
|
171
|
+
add_rom(rom)
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
# Add ROM
|
176
|
+
#
|
177
|
+
# @param [ROM] rom ROM to add
|
178
|
+
#
|
179
|
+
# @return self
|
180
|
+
#
|
181
|
+
def add_rom(rom)
|
182
|
+
# Sanity check
|
183
|
+
unless ROM === rom
|
184
|
+
raise ArgumentError, "not a ROM"
|
185
|
+
end
|
186
|
+
|
187
|
+
# Add it to the list
|
188
|
+
@roms << rom
|
189
|
+
|
190
|
+
# Keep track of checksums
|
191
|
+
@cksum.each {|type, hlist|
|
192
|
+
hlist.merge!(rom.cksum(type) => rom) {|key, old, new|
|
193
|
+
if Array(old).any? {|r| r.path == new.path}
|
194
|
+
then old
|
195
|
+
else Array(old) + [ new ]
|
196
|
+
end
|
197
|
+
}
|
198
|
+
}
|
199
|
+
|
200
|
+
# Chainable
|
201
|
+
self
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
# Add ROM from file
|
206
|
+
#
|
207
|
+
# @param file [String] path to files relative to basedir
|
208
|
+
# @param basedir [String,nil] base directory
|
209
|
+
# @param archives [#include?] archives tester
|
210
|
+
#
|
211
|
+
# @return [self]
|
212
|
+
#
|
213
|
+
def add_from_file(file, basedir = nil, archives: ARCHIVES)
|
214
|
+
filepath = File.join(*[ basedir, file ].compact)
|
215
|
+
romlist = if ROMArchive.archive?(filepath, archives: archives)
|
216
|
+
then ROMArchive.from_file(filepath).to_a
|
217
|
+
else ROM.from_file(file, basedir)
|
218
|
+
end
|
219
|
+
|
220
|
+
Array(romlist).each {|rom| add_rom(rom) }
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
# Add ROM from directory.
|
225
|
+
# @note file in {IGNORE_FILES}, directory in {IGNORE_DIRS},
|
226
|
+
# directories holding a {DIR_PRUNING} file or starting with a
|
227
|
+
# dot are ignored
|
228
|
+
#
|
229
|
+
# @param dir [String] path to directory
|
230
|
+
# @param depth [Integer,nil] exploration depth
|
231
|
+
# @param archives [#include?] archives tester
|
232
|
+
#
|
233
|
+
# @yieldparam file [String] file being processed
|
234
|
+
# @yieldparam dir [String] directory relative to
|
235
|
+
#
|
236
|
+
# @return [self]
|
237
|
+
#
|
238
|
+
def add_from_dir(dir, depth: nil, archives: ARCHIVES)
|
239
|
+
Vault.from_dir(dir, depth: depth) do | file, dir: |
|
240
|
+
yield(file, dir: dir) if block_given?
|
241
|
+
add_from_file(file, dir, archives: archives)
|
242
|
+
end
|
243
|
+
self
|
244
|
+
end
|
245
|
+
|
246
|
+
|
247
|
+
# Add ROM from glob
|
248
|
+
# @note file in {IGNORE_FILES}, directory in {IGNORE_DIRS},
|
249
|
+
# directories holding a {DIR_PRUNING} file or starting with a
|
250
|
+
# dot are ignored
|
251
|
+
#
|
252
|
+
# @param glob [String] ruby glob
|
253
|
+
# @param basedir [:guess,nil] basedir to use when interpreting glob
|
254
|
+
# matching
|
255
|
+
# @param archives [#include?] archives tester
|
256
|
+
#
|
257
|
+
# @yieldparam file [String] file being processed
|
258
|
+
# @yieldparam dir [String] directory relative to
|
259
|
+
#
|
260
|
+
# @return [self]
|
261
|
+
#
|
262
|
+
def add_from_glob(glob, basedir: :guess, archives: ARCHIVES)
|
263
|
+
Vault.from_dir(glob, basedir: basedir) do | file, dir: |
|
264
|
+
yield(file, dir: dir) if block_given?
|
265
|
+
add_from_file(file, dir, archives: archives)
|
266
|
+
end
|
267
|
+
self
|
268
|
+
end
|
269
|
+
|
270
|
+
|
271
|
+
# List of ROM with loosely defined (ie: with some missing checksum)
|
272
|
+
#
|
273
|
+
# @return [Array<ROM>,nil]
|
274
|
+
#
|
275
|
+
def with_partial_checksum
|
276
|
+
@roms.select {|rom| rom.missing_checksums? }
|
277
|
+
end
|
278
|
+
|
279
|
+
|
280
|
+
# Check if we have some headered ROM.
|
281
|
+
#
|
282
|
+
# @return [Integer] only some ROMs are headered
|
283
|
+
# @return [true] all ROMs are headered
|
284
|
+
# @return [false] no headered ROM
|
285
|
+
#
|
286
|
+
def headered
|
287
|
+
size = @roms.select {|rom| rom.headered? }.size
|
288
|
+
|
289
|
+
if size == 0 then false
|
290
|
+
elsif size == @roms.size then true
|
291
|
+
else size
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
# Return list of matching ROMs.
|
296
|
+
#
|
297
|
+
# @param query [Hash{Symbol=>String}] Hash of checksums to match with
|
298
|
+
#
|
299
|
+
# @return [Array<ROM>] list of matching ROMs
|
300
|
+
# @return [nil] if no match
|
301
|
+
#
|
302
|
+
def cksummatch(query)
|
303
|
+
CHECKSUMS.each {|type|
|
304
|
+
if (q = query[type]) && (r = @cksum[type][q])
|
305
|
+
return Array(r)
|
306
|
+
end
|
307
|
+
}
|
308
|
+
return nil
|
309
|
+
end
|
310
|
+
|
311
|
+
# Return list of matching ROMs.
|
312
|
+
#
|
313
|
+
# @param rom [ROM] ROM to match with
|
314
|
+
#
|
315
|
+
# @return [Array<ROM>] list of matching ROMs
|
316
|
+
# @return [nil] if no match
|
317
|
+
#
|
318
|
+
def rommatch(rom)
|
319
|
+
self.cksummatch(rom.cksums)
|
320
|
+
end
|
321
|
+
|
322
|
+
|
323
|
+
# Return list of matching ROMs.
|
324
|
+
#
|
325
|
+
# @param query [Hash{Symbol=>String},ROM] Hash of checksums or ROM
|
326
|
+
# to match with
|
327
|
+
#
|
328
|
+
# @yieldparam rom [ROM] ROM that has been saved
|
329
|
+
#
|
330
|
+
# @return [Array<ROM>] list of matching ROMs
|
331
|
+
# @return [nil] if no match
|
332
|
+
#
|
333
|
+
def match(query)
|
334
|
+
case query
|
335
|
+
when Hash then self.cksummatch(query)
|
336
|
+
when ROM then self.rommatch(query)
|
337
|
+
else raise ArgumentError
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
|
342
|
+
# Save ROM to filesystem
|
343
|
+
#
|
344
|
+
# @param dir [String] directory used for saving
|
345
|
+
# @param part [:all,:header,:rom] wich part of the ROM file to save
|
346
|
+
# @param subdir [Boolean,Integer,Proc] use subdirectory
|
347
|
+
# @param pristine [Boolean] should existing directory be removed
|
348
|
+
# @param force [Boolean] remove previous file if necessary
|
349
|
+
#
|
350
|
+
# @yieldparam rom [ROM] ROM saved
|
351
|
+
#
|
352
|
+
# @return [self]
|
353
|
+
#
|
354
|
+
def save(dir, part: :all, subdir: false, pristine: false, force: false,
|
355
|
+
&block)
|
356
|
+
# Directory
|
357
|
+
FileUtils.remove_dir(dir) if pristine # Create clean env
|
358
|
+
Dir.mkdir(dir) unless Dir.exist?(dir) # Ensure directory
|
359
|
+
|
360
|
+
# Fill directory.
|
361
|
+
# -> We have the physical ROMs, so we have all the checksums
|
362
|
+
# except if the file is an header without rom content
|
363
|
+
@roms.select {|rom| rom.has_content? && !rom.fshash.nil? }
|
364
|
+
.each {|rom|
|
365
|
+
hash = rom.fshash
|
366
|
+
destdir = dir
|
367
|
+
dirpart = case subdir
|
368
|
+
when nil, false then nil
|
369
|
+
when true then hash[0..3]
|
370
|
+
when Integer then hash[0..subdir]
|
371
|
+
when Proc then subdir.call(rom)
|
372
|
+
else raise ArgumentError, "unsupported subdir type"
|
373
|
+
end
|
374
|
+
|
375
|
+
if dirpart
|
376
|
+
# Update destination directory
|
377
|
+
destdir = File.join(destdir, *dirpart)
|
378
|
+
# Ensure destination directory exists
|
379
|
+
FileUtils.mkdir_p(destdir)
|
380
|
+
end
|
381
|
+
|
382
|
+
# Destination file
|
383
|
+
dest = File.join(destdir, hash)
|
384
|
+
|
385
|
+
# If the file exist, it is the right file, as it is
|
386
|
+
# named from it's hash (ie: content)
|
387
|
+
if force || !File.exists?(dest)
|
388
|
+
rom.copy(dest, part: part, force: force)
|
389
|
+
end
|
390
|
+
|
391
|
+
block.call(rom) if block
|
392
|
+
}
|
393
|
+
self
|
394
|
+
end
|
395
|
+
|
396
|
+
|
397
|
+
# Dumping of ROM vault entries
|
398
|
+
#
|
399
|
+
# @param compact [Boolean]
|
400
|
+
#
|
401
|
+
# @return [self]
|
402
|
+
#
|
403
|
+
# @yieldparam group [String]
|
404
|
+
# @yieldparam entries [Array<String>]
|
405
|
+
#
|
406
|
+
def dump(compact: false, &block)
|
407
|
+
self.each.inject({}) {|grp, rom|
|
408
|
+
grp.merge(rom.path.storage => [rom]) {|key, old, new| old + new }
|
409
|
+
}.each {|storage, roms|
|
410
|
+
size = if ROM::Path::Archive === roms.first.path
|
411
|
+
roms.first.path.archive.size
|
412
|
+
end
|
413
|
+
|
414
|
+
if storage.nil?
|
415
|
+
roms.each {|rom| block.call(rom.path.entry, nil) }
|
416
|
+
else
|
417
|
+
if compact && (size == roms.size)
|
418
|
+
then block.call(storage)
|
419
|
+
else block.call(storage, roms.map {|r| r.path.entry })
|
420
|
+
end
|
421
|
+
end
|
422
|
+
}
|
423
|
+
self
|
424
|
+
end
|
425
|
+
|
426
|
+
protected
|
427
|
+
|
428
|
+
def roms
|
429
|
+
@roms
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
end
|
metadata
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rom-distillery
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stephane D'Alu
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-05-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nokogiri
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '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'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rubyzip
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: tty-screen
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: tty-logger
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: tty-spinner
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: tty-progressbar
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: yard
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: Help organise emulation ROM using DAT file
|
126
|
+
email:
|
127
|
+
- sdalu@sdalu.com
|
128
|
+
executables:
|
129
|
+
- rhum
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- Gemfile
|
134
|
+
- LICENSE
|
135
|
+
- README.md
|
136
|
+
- bin/rhum
|
137
|
+
- distillery.gemspec
|
138
|
+
- lib/distillery.rb
|
139
|
+
- lib/distillery/archiver.rb
|
140
|
+
- lib/distillery/archiver/archive.rb
|
141
|
+
- lib/distillery/archiver/external.rb
|
142
|
+
- lib/distillery/archiver/external.yaml
|
143
|
+
- lib/distillery/archiver/libarchive.rb
|
144
|
+
- lib/distillery/archiver/zip.rb
|
145
|
+
- lib/distillery/cli.rb
|
146
|
+
- lib/distillery/cli/check.rb
|
147
|
+
- lib/distillery/cli/clean.rb
|
148
|
+
- lib/distillery/cli/header.rb
|
149
|
+
- lib/distillery/cli/index.rb
|
150
|
+
- lib/distillery/cli/overlap.rb
|
151
|
+
- lib/distillery/cli/rebuild.rb
|
152
|
+
- lib/distillery/cli/rename.rb
|
153
|
+
- lib/distillery/cli/repack.rb
|
154
|
+
- lib/distillery/cli/validate.rb
|
155
|
+
- lib/distillery/datfile.rb
|
156
|
+
- lib/distillery/error.rb
|
157
|
+
- lib/distillery/game.rb
|
158
|
+
- lib/distillery/game/release.rb
|
159
|
+
- lib/distillery/refinements.rb
|
160
|
+
- lib/distillery/rom-archive.rb
|
161
|
+
- lib/distillery/rom.rb
|
162
|
+
- lib/distillery/rom/path.rb
|
163
|
+
- lib/distillery/rom/path/archive.rb
|
164
|
+
- lib/distillery/rom/path/file.rb
|
165
|
+
- lib/distillery/rom/path/virtual.rb
|
166
|
+
- lib/distillery/storage.rb
|
167
|
+
- lib/distillery/vault.rb
|
168
|
+
- lib/distillery/version.rb
|
169
|
+
homepage: http://github.com/sdalu/distillery
|
170
|
+
licenses:
|
171
|
+
- EUPL-1.2
|
172
|
+
metadata: {}
|
173
|
+
post_install_message:
|
174
|
+
rdoc_options: []
|
175
|
+
require_paths:
|
176
|
+
- lib
|
177
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '2.5'
|
182
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
187
|
+
requirements: []
|
188
|
+
rubygems_version: 3.0.6
|
189
|
+
signing_key:
|
190
|
+
specification_version: 4
|
191
|
+
summary: ROM manager
|
192
|
+
test_files: []
|