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,102 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # SPDX-License-Identifier: EUPL-1.2
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Distillery
         
     | 
| 
      
 4 
     | 
    
         
            +
            class Archiver
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            # Allow archive file processing
         
     | 
| 
      
 7 
     | 
    
         
            +
            #
         
     | 
| 
      
 8 
     | 
    
         
            +
            # All the operations are forwarded to an {Archiver} instance
         
     | 
| 
      
 9 
     | 
    
         
            +
            # which is able to process the selected archive file.
         
     | 
| 
      
 10 
     | 
    
         
            +
            #   
         
     | 
| 
      
 11 
     | 
    
         
            +
            class Archive
         
     | 
| 
      
 12 
     | 
    
         
            +
                include Enumerable
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                # Returns a new instance of Archive.
         
     | 
| 
      
 15 
     | 
    
         
            +
                #
         
     | 
| 
      
 16 
     | 
    
         
            +
                # @param file [String]		file holding the archive
         
     | 
| 
      
 17 
     | 
    
         
            +
                #
         
     | 
| 
      
 18 
     | 
    
         
            +
                # @raise [ArchiverNotFound]		an archiver able to process this file
         
     | 
| 
      
 19 
     | 
    
         
            +
                #					has not been found
         
     | 
| 
      
 20 
     | 
    
         
            +
                #
         
     | 
| 
      
 21 
     | 
    
         
            +
                def initialize(file)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @file     = file
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @archiver = Archiver.for_file(file)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    if @archiver.nil?
         
     | 
| 
      
 26 
     | 
    
         
            +
                        raise ArchiverNotFound, "no archiver avalaible for this file"
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                
         
     | 
| 
      
 31 
     | 
    
         
            +
                # Iterate over each archive entry
         
     | 
| 
      
 32 
     | 
    
         
            +
                #
         
     | 
| 
      
 33 
     | 
    
         
            +
                # @yieldparam entry [String]	entry name
         
     | 
| 
      
 34 
     | 
    
         
            +
                # @yieldparam io    [InputStream]	input stream
         
     | 
| 
      
 35 
     | 
    
         
            +
                #
         
     | 
| 
      
 36 
     | 
    
         
            +
                # @return [self,Enumerator]
         
     | 
| 
      
 37 
     | 
    
         
            +
                #
         
     | 
| 
      
 38 
     | 
    
         
            +
                def each(&block)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    @archiver.each(@file, &block)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    self
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                
         
     | 
| 
      
 44 
     | 
    
         
            +
                # List of entries for the archive
         
     | 
| 
      
 45 
     | 
    
         
            +
                #
         
     | 
| 
      
 46 
     | 
    
         
            +
                # @return [Array<String>]
         
     | 
| 
      
 47 
     | 
    
         
            +
                #
         
     | 
| 
      
 48 
     | 
    
         
            +
                def entries
         
     | 
| 
      
 49 
     | 
    
         
            +
                    @archiver.entries(@file)
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                # Is the archive emtpy?
         
     | 
| 
      
 54 
     | 
    
         
            +
                #
         
     | 
| 
      
 55 
     | 
    
         
            +
                # @return [Boolean]
         
     | 
| 
      
 56 
     | 
    
         
            +
                #
         
     | 
| 
      
 57 
     | 
    
         
            +
                def empty?
         
     | 
| 
      
 58 
     | 
    
         
            +
                    @archiver.empty?(@file)
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                
         
     | 
| 
      
 62 
     | 
    
         
            +
                # Allow to perform read operation on an archive entry
         
     | 
| 
      
 63 
     | 
    
         
            +
                #
         
     | 
| 
      
 64 
     | 
    
         
            +
                # @param entry [String]		entry name
         
     | 
| 
      
 65 
     | 
    
         
            +
                #
         
     | 
| 
      
 66 
     | 
    
         
            +
                # @yieldparam io [InputStream]	input stream for reading
         
     | 
| 
      
 67 
     | 
    
         
            +
                #
         
     | 
| 
      
 68 
     | 
    
         
            +
                # @return 				block value
         
     | 
| 
      
 69 
     | 
    
         
            +
                #
         
     | 
| 
      
 70 
     | 
    
         
            +
                def reader(entry, &block)
         
     | 
| 
      
 71 
     | 
    
         
            +
                    @archiver.reader(@file, entry, &block)
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                
         
     | 
| 
      
 75 
     | 
    
         
            +
                # Allow to perform write operation on an archive entry
         
     | 
| 
      
 76 
     | 
    
         
            +
                #
         
     | 
| 
      
 77 
     | 
    
         
            +
                # @param entry [String]		entry name
         
     | 
| 
      
 78 
     | 
    
         
            +
                #
         
     | 
| 
      
 79 
     | 
    
         
            +
                # @yieldparam io [OutputStream]	output stream for writing
         
     | 
| 
      
 80 
     | 
    
         
            +
                #
         
     | 
| 
      
 81 
     | 
    
         
            +
                # @return 				block value
         
     | 
| 
      
 82 
     | 
    
         
            +
                #
         
     | 
| 
      
 83 
     | 
    
         
            +
                def writer(entry, &block)
         
     | 
| 
      
 84 
     | 
    
         
            +
                    @archiver.writer(@file, entry, &block)
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                
         
     | 
| 
      
 88 
     | 
    
         
            +
                # Delete the entry from the archive
         
     | 
| 
      
 89 
     | 
    
         
            +
                #
         
     | 
| 
      
 90 
     | 
    
         
            +
                # @param entry [String]		entry name
         
     | 
| 
      
 91 
     | 
    
         
            +
                #
         
     | 
| 
      
 92 
     | 
    
         
            +
                # @return [Boolean]		operation status
         
     | 
| 
      
 93 
     | 
    
         
            +
                #
         
     | 
| 
      
 94 
     | 
    
         
            +
                def delete!(entry)
         
     | 
| 
      
 95 
     | 
    
         
            +
                    @archiver.delete!(@file, entry)
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                
         
     | 
| 
      
 99 
     | 
    
         
            +
            end
         
     | 
| 
      
 100 
     | 
    
         
            +
                
         
     | 
| 
      
 101 
     | 
    
         
            +
            end
         
     | 
| 
      
 102 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,182 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # SPDX-License-Identifier: EUPL-1.2
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'open3'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Distillery
         
     | 
| 
      
 7 
     | 
    
         
            +
            class Archiver
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            # Use external program to process archive
         
     | 
| 
      
 10 
     | 
    
         
            +
            # Selection of external program is described in external.yaml
         
     | 
| 
      
 11 
     | 
    
         
            +
            #
         
     | 
| 
      
 12 
     | 
    
         
            +
            class External < Archiver
         
     | 
| 
      
 13 
     | 
    
         
            +
                Archiver.add self
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                # Perform registration of the various archive format
         
     | 
| 
      
 16 
     | 
    
         
            +
                # supported by this archiver provider
         
     | 
| 
      
 17 
     | 
    
         
            +
                #
         
     | 
| 
      
 18 
     | 
    
         
            +
                # @param list         [Array<String>]	list of format to register
         
     | 
| 
      
 19 
     | 
    
         
            +
                # @param default_file [String]		default configuration file
         
     | 
| 
      
 20 
     | 
    
         
            +
                #
         
     | 
| 
      
 21 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 22 
     | 
    
         
            +
                #
         
     | 
| 
      
 23 
     | 
    
         
            +
                def self.registering(list         = [ '7z', 'zip' ],
         
     | 
| 
      
 24 
     | 
    
         
            +
                                     default_file = File.join(__dir__, 'external.yaml'))
         
     | 
| 
      
 25 
     | 
    
         
            +
                    dflt_config = YAML.load_file(default_file)
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    if Array === list
         
     | 
| 
      
 28 
     | 
    
         
            +
                        list = Hash[list.map {|app| [ app, {} ] }]
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    list.each {|app, cfg|
         
     | 
| 
      
 32 
     | 
    
         
            +
                        dflt       = dflt_config.dig(app) || {}
         
     | 
| 
      
 33 
     | 
    
         
            +
                        extensions = Array(cfg.dig('extension')  || dflt.dig('extension'))
         
     | 
| 
      
 34 
     | 
    
         
            +
                        mimetypes  = Array(cfg.dig('mimetype' )  || dflt.dig('mimetype' ))
         
     | 
| 
      
 35 
     | 
    
         
            +
                        list       = {
         
     | 
| 
      
 36 
     | 
    
         
            +
                            :cmd    => cfg .dig('list', 'cmd')   || cfg .dig('cmd') ||
         
     | 
| 
      
 37 
     | 
    
         
            +
                                       dflt.dig('list', 'cmd')   || dflt.dig('cmd'),
         
     | 
| 
      
 38 
     | 
    
         
            +
                            :args   => cfg .dig('list', 'args')  ||
         
     | 
| 
      
 39 
     | 
    
         
            +
                                       dflt.dig('list', 'args'),
         
     | 
| 
      
 40 
     | 
    
         
            +
                            :parser => if parser = (cfg .dig('list', 'parser')      ||
         
     | 
| 
      
 41 
     | 
    
         
            +
                                                    dflt.dig('list', 'parser'))
         
     | 
| 
      
 42 
     | 
    
         
            +
                                           Regexp.new('\A' + parser + '\Z')
         
     | 
| 
      
 43 
     | 
    
         
            +
                                       end,
         
     | 
| 
      
 44 
     | 
    
         
            +
                            :validator => cfg .dig('list', 'validator') ||
         
     | 
| 
      
 45 
     | 
    
         
            +
                                          dflt.dig('list', 'validator')
         
     | 
| 
      
 46 
     | 
    
         
            +
                        }
         
     | 
| 
      
 47 
     | 
    
         
            +
                        read       = {
         
     | 
| 
      
 48 
     | 
    
         
            +
                            :cmd    => cfg .dig('read', 'cmd')   || cfg .dig('cmd') ||
         
     | 
| 
      
 49 
     | 
    
         
            +
                                       dflt.dig('read', 'cmd')   || dflt.dig('cmd'),
         
     | 
| 
      
 50 
     | 
    
         
            +
                            :args   => cfg .dig('read', 'args')  ||
         
     | 
| 
      
 51 
     | 
    
         
            +
                                       dflt.dig('read', 'args'),
         
     | 
| 
      
 52 
     | 
    
         
            +
                        }
         
     | 
| 
      
 53 
     | 
    
         
            +
                        write      = {
         
     | 
| 
      
 54 
     | 
    
         
            +
                            :cmd    => cfg .dig('write', 'cmd')  || cfg .dig('cmd') ||
         
     | 
| 
      
 55 
     | 
    
         
            +
                                       dflt.dig('write', 'cmd')  || dflt.dig('cmd'),
         
     | 
| 
      
 56 
     | 
    
         
            +
                            :args   => cfg .dig('write', 'args') ||
         
     | 
| 
      
 57 
     | 
    
         
            +
                                       dflt.dig('write', 'args'),
         
     | 
| 
      
 58 
     | 
    
         
            +
                        }
         
     | 
| 
      
 59 
     | 
    
         
            +
                        delete     = {
         
     | 
| 
      
 60 
     | 
    
         
            +
                            :cmd    => cfg .dig('delete', 'cmd')  || cfg .dig('cmd') ||
         
     | 
| 
      
 61 
     | 
    
         
            +
                                       dflt.dig('delete', 'cmd')  || dflt.dig('cmd'),
         
     | 
| 
      
 62 
     | 
    
         
            +
                            :args   => cfg .dig('delete', 'args') ||
         
     | 
| 
      
 63 
     | 
    
         
            +
                                       dflt.dig('delete', 'args'),
         
     | 
| 
      
 64 
     | 
    
         
            +
                        }
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                        if list[:cmd].nil? || read[:cmd].nil?
         
     | 
| 
      
 67 
     | 
    
         
            +
                            Archiver.logger&.warn {
         
     | 
| 
      
 68 
     | 
    
         
            +
                                "#{self}: command not defined for #{app} program (SKIP)"
         
     | 
| 
      
 69 
     | 
    
         
            +
                            }
         
     | 
| 
      
 70 
     | 
    
         
            +
                            next
         
     | 
| 
      
 71 
     | 
    
         
            +
                        end
         
     | 
| 
      
 72 
     | 
    
         
            +
                        if write[:cmd].nil?
         
     | 
| 
      
 73 
     | 
    
         
            +
                            Archiver.logger&.warn {
         
     | 
| 
      
 74 
     | 
    
         
            +
                                "#{self}: write mode not supported for #{app} program"
         
     | 
| 
      
 75 
     | 
    
         
            +
                            }
         
     | 
| 
      
 76 
     | 
    
         
            +
                        end
         
     | 
| 
      
 77 
     | 
    
         
            +
                            
         
     | 
| 
      
 78 
     | 
    
         
            +
                        Archiver.register(External.new(list, read, write, delete,
         
     | 
| 
      
 79 
     | 
    
         
            +
                                                       extensions: extensions,
         
     | 
| 
      
 80 
     | 
    
         
            +
                                                        mimetypes: mimetypes))
         
     | 
| 
      
 81 
     | 
    
         
            +
                    }
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
                
         
     | 
| 
      
 84 
     | 
    
         
            +
                def initialize(list, read, write=nil, delete=nil,
         
     | 
| 
      
 85 
     | 
    
         
            +
                               extensions:, mimetypes: nil)
         
     | 
| 
      
 86 
     | 
    
         
            +
                    @list       = list
         
     | 
| 
      
 87 
     | 
    
         
            +
                    @read       = read
         
     | 
| 
      
 88 
     | 
    
         
            +
                    @write      = write
         
     | 
| 
      
 89 
     | 
    
         
            +
                    @delete     = delete
         
     | 
| 
      
 90 
     | 
    
         
            +
                    @extensions = extensions
         
     | 
| 
      
 91 
     | 
    
         
            +
                    @mimetypes  = mimetypes
         
     | 
| 
      
 92 
     | 
    
         
            +
                end
         
     | 
| 
      
 93 
     | 
    
         
            +
                
         
     | 
| 
      
 94 
     | 
    
         
            +
                            
         
     | 
| 
      
 95 
     | 
    
         
            +
                # (see Archiver#extensions)
         
     | 
| 
      
 96 
     | 
    
         
            +
                def extensions
         
     | 
| 
      
 97 
     | 
    
         
            +
                    @extensions
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                
         
     | 
| 
      
 101 
     | 
    
         
            +
                # (see Archiver#mimetypes)
         
     | 
| 
      
 102 
     | 
    
         
            +
                def mimetypes
         
     | 
| 
      
 103 
     | 
    
         
            +
                    @mimetypes
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                # (see Archiver#each)
         
     | 
| 
      
 107 
     | 
    
         
            +
                def each(file, &block)
         
     | 
| 
      
 108 
     | 
    
         
            +
                    return to_enum(:each, file) if block.nil?
         
     | 
| 
      
 109 
     | 
    
         
            +
                    entries(file).each {|entry|
         
     | 
| 
      
 110 
     | 
    
         
            +
                        reader(file, entry) {|io|
         
     | 
| 
      
 111 
     | 
    
         
            +
                            block.call(entry, io)
         
     | 
| 
      
 112 
     | 
    
         
            +
                        }
         
     | 
| 
      
 113 
     | 
    
         
            +
                    }
         
     | 
| 
      
 114 
     | 
    
         
            +
                end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                # (see Archiver#reader)
         
     | 
| 
      
 117 
     | 
    
         
            +
                def reader(file, entry, &block)
         
     | 
| 
      
 118 
     | 
    
         
            +
                    subst = { '$(infile)' => file, '$(entry)' => entry  }
         
     | 
| 
      
 119 
     | 
    
         
            +
                    cmd   = @read[:cmd ]
         
     | 
| 
      
 120 
     | 
    
         
            +
                    args  = @read[:args].map{|e| e.gsub(/\$\(\w+\)/, subst) }
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                    Open3.popen2(cmd, *args) {|stdin, stdout|
         
     | 
| 
      
 123 
     | 
    
         
            +
                        stdin.close_write
         
     | 
| 
      
 124 
     | 
    
         
            +
                        block.call(InputStream.new(stdout))
         
     | 
| 
      
 125 
     | 
    
         
            +
                    }
         
     | 
| 
      
 126 
     | 
    
         
            +
                end
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                # (see Archiver#writer)
         
     | 
| 
      
 129 
     | 
    
         
            +
                def writer(file, entry, &block)
         
     | 
| 
      
 130 
     | 
    
         
            +
                    subst = { '$(infile)' => file, '$(entry)' => entry  }
         
     | 
| 
      
 131 
     | 
    
         
            +
                    cmd   = @write[:cmd ]
         
     | 
| 
      
 132 
     | 
    
         
            +
                    args  = @write[:args].map{|e| e.gsub(/\$\(\w+\)/, subst) }
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                    Open3.popen2(cmd, *args) {|stdin, stdout|
         
     | 
| 
      
 135 
     | 
    
         
            +
                        block.call(OutputStream.new(stdin))
         
     | 
| 
      
 136 
     | 
    
         
            +
                    }
         
     | 
| 
      
 137 
     | 
    
         
            +
                end
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                # (see Archiver#delete!)
         
     | 
| 
      
 140 
     | 
    
         
            +
                def delete!(file, entry)
         
     | 
| 
      
 141 
     | 
    
         
            +
                    subst = { '$(infile)' => file, '$(entry)' => entry  }
         
     | 
| 
      
 142 
     | 
    
         
            +
                    cmd   = @delete[:cmd ]
         
     | 
| 
      
 143 
     | 
    
         
            +
                    args  = @delete[:args].map{|e| e.gsub(/\$\(\w+\)/, subst) }
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                    Open3.popen2(cmd, *args) {|stdin, stdout|
         
     | 
| 
      
 146 
     | 
    
         
            +
                        stdin.close_write
         
     | 
| 
      
 147 
     | 
    
         
            +
                    }
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                    true
         
     | 
| 
      
 150 
     | 
    
         
            +
                end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                # (see Archiver#entries)
         
     | 
| 
      
 153 
     | 
    
         
            +
                def entries(file)
         
     | 
| 
      
 154 
     | 
    
         
            +
                    subst     = { '$(infile)' => file }
         
     | 
| 
      
 155 
     | 
    
         
            +
                    cmd       = @list[:cmd      ]
         
     | 
| 
      
 156 
     | 
    
         
            +
                    args      = @list[:args     ].map{|e| e.gsub(/\$\(\w+\)/, subst) }
         
     | 
| 
      
 157 
     | 
    
         
            +
                    parser    = @list[:parser   ]
         
     | 
| 
      
 158 
     | 
    
         
            +
                    validator = @list[:validator]
         
     | 
| 
      
 159 
     | 
    
         
            +
                    
         
     | 
| 
      
 160 
     | 
    
         
            +
                    stdout, stderr, status = Open3.capture3(cmd, *args)
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                    if ! status.exitstatus.zero?
         
     | 
| 
      
 163 
     | 
    
         
            +
                        raise ExecError, "running external command failed (#{stderr})"
         
     | 
| 
      
 164 
     | 
    
         
            +
                    end
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
                    stdout.force_encoding('BINARY').lines(chomp: true).map {|l|
         
     | 
| 
      
 167 
     | 
    
         
            +
                        unless m = l.match(parser)
         
     | 
| 
      
 168 
     | 
    
         
            +
                            raise ProcessingError, "unable to parse entry (#{file}) (#{l})"
         
     | 
| 
      
 169 
     | 
    
         
            +
                        end
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                        if validator && validator.find {|k,v| m[k] != v }
         
     | 
| 
      
 172 
     | 
    
         
            +
                            next
         
     | 
| 
      
 173 
     | 
    
         
            +
                        end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                        m[:entry]
         
     | 
| 
      
 176 
     | 
    
         
            +
                    }.compact
         
     | 
| 
      
 177 
     | 
    
         
            +
                end
         
     | 
| 
      
 178 
     | 
    
         
            +
            end
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
            end
         
     | 
| 
      
 181 
     | 
    
         
            +
            end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # SPDX-License-Identifier: EUPL-1.2
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            7z:
         
     | 
| 
      
 4 
     | 
    
         
            +
              extension: 7z
         
     | 
| 
      
 5 
     | 
    
         
            +
              mimetype: application/x-7z-compressed
         
     | 
| 
      
 6 
     | 
    
         
            +
              cmd: 7z
         
     | 
| 
      
 7 
     | 
    
         
            +
              list:
         
     | 
| 
      
 8 
     | 
    
         
            +
                args: [ l, -ba, $(infile) ]
         
     | 
| 
      
 9 
     | 
    
         
            +
                parser: (?:\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})?\s+(?<type>.)....\s+\d+\s+(?:\d+\s+)?(?<entry>.+)
         
     | 
| 
      
 10 
     | 
    
         
            +
                validator:
         
     | 
| 
      
 11 
     | 
    
         
            +
                  :type: '.'
         
     | 
| 
      
 12 
     | 
    
         
            +
              read:
         
     | 
| 
      
 13 
     | 
    
         
            +
                args: [ e, -so, $(infile), $(entry) ]
         
     | 
| 
      
 14 
     | 
    
         
            +
              write:
         
     | 
| 
      
 15 
     | 
    
         
            +
                args: [ a, $(infile), -m0=lzma, -mx=9, -si$(entry) ]
         
     | 
| 
      
 16 
     | 
    
         
            +
              delete:
         
     | 
| 
      
 17 
     | 
    
         
            +
                args: [ d, $(infile), $(entry) ]
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            zip:
         
     | 
| 
      
 20 
     | 
    
         
            +
              extension: zip
         
     | 
| 
      
 21 
     | 
    
         
            +
              mimetype: application/zip
         
     | 
| 
      
 22 
     | 
    
         
            +
              list:
         
     | 
| 
      
 23 
     | 
    
         
            +
                cmd: unzip
         
     | 
| 
      
 24 
     | 
    
         
            +
                args: [ -Z1, $(infile) ]
         
     | 
| 
      
 25 
     | 
    
         
            +
                parser: (?<entry>.+)
         
     | 
| 
      
 26 
     | 
    
         
            +
              read:
         
     | 
| 
      
 27 
     | 
    
         
            +
                cmd: unzip
         
     | 
| 
      
 28 
     | 
    
         
            +
                args: [ -p, $(infile), $(entry) ]
         
     | 
| 
      
 29 
     | 
    
         
            +
              delete:
         
     | 
| 
      
 30 
     | 
    
         
            +
                cmd: zip
         
     | 
| 
      
 31 
     | 
    
         
            +
                args: [ -d, $(infile), $(entry) ]
         
     | 
| 
         @@ -0,0 +1,105 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # SPDX-License-Identifier: EUPL-1.2
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            begin
         
     | 
| 
      
 4 
     | 
    
         
            +
                require 'libarchive'
         
     | 
| 
      
 5 
     | 
    
         
            +
            rescue LoadError
         
     | 
| 
      
 6 
     | 
    
         
            +
                return
         
     | 
| 
      
 7 
     | 
    
         
            +
            end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            module Distillery
         
     | 
| 
      
 11 
     | 
    
         
            +
            class Archiver
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            # Use binding to libarchive
         
     | 
| 
      
 14 
     | 
    
         
            +
            #
         
     | 
| 
      
 15 
     | 
    
         
            +
            class LibArchive < Archiver
         
     | 
| 
      
 16 
     | 
    
         
            +
                Archiver.add self
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                MODE = { '7z'  => { :extensions =>  '7z',
         
     | 
| 
      
 19 
     | 
    
         
            +
                                    :mimetypes  => 'application/x-7z-compressed' },
         
     | 
| 
      
 20 
     | 
    
         
            +
                         'zip' => { :extensions => 'zip',
         
     | 
| 
      
 21 
     | 
    
         
            +
                                    :mimetypes  => 'application/zip'             },
         
     | 
| 
      
 22 
     | 
    
         
            +
                       }
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                class InputStream < Archiver::InputStream
         
     | 
| 
      
 26 
     | 
    
         
            +
                    def initialize(ar)
         
     | 
| 
      
 27 
     | 
    
         
            +
                        @read_block = ar.to_enum(:read_data, 16*1024)
         
     | 
| 
      
 28 
     | 
    
         
            +
                        @buffer     = StringIO.new
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    def read(length=nil)
         
     | 
| 
      
 32 
     | 
    
         
            +
                        return ''  if length&.zero?		# Zero length request
         
     | 
| 
      
 33 
     | 
    
         
            +
                        return nil if @buffer.nil?		# End of stream
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                        # Read data
         
     | 
| 
      
 36 
     | 
    
         
            +
                        data = @buffer.read(length) || ""
         
     | 
| 
      
 37 
     | 
    
         
            +
                        while data.size < length do
         
     | 
| 
      
 38 
     | 
    
         
            +
                            # We are short on data, that means buffer has been exhausted
         
     | 
| 
      
 39 
     | 
    
         
            +
                            # request new data block from the archive
         
     | 
| 
      
 40 
     | 
    
         
            +
                            block = @read_block.next
         
     | 
| 
      
 41 
     | 
    
         
            +
                            # Break if we already read all the archive data
         
     | 
| 
      
 42 
     | 
    
         
            +
                            if block.nil? || block.empty?
         
     | 
| 
      
 43 
     | 
    
         
            +
                                @buffer = nil
         
     | 
| 
      
 44 
     | 
    
         
            +
                                break
         
     | 
| 
      
 45 
     | 
    
         
            +
                            end
         
     | 
| 
      
 46 
     | 
    
         
            +
                            # Refill buffer from block
         
     | 
| 
      
 47 
     | 
    
         
            +
                            @buffer.string = block
         
     | 
| 
      
 48 
     | 
    
         
            +
                            # Continue reading
         
     | 
| 
      
 49 
     | 
    
         
            +
                            data.concat(@buffer.read(length - data.size))
         
     | 
| 
      
 50 
     | 
    
         
            +
                        end
         
     | 
| 
      
 51 
     | 
    
         
            +
                        
         
     | 
| 
      
 52 
     | 
    
         
            +
                        data.empty? ? nil : data
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
                
         
     | 
| 
      
 56 
     | 
    
         
            +
                
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                
         
     | 
| 
      
 59 
     | 
    
         
            +
                def self.registering
         
     | 
| 
      
 60 
     | 
    
         
            +
                    MODE.each_key {|mode|
         
     | 
| 
      
 61 
     | 
    
         
            +
                        Archiver.register(LibArchive.new(mode))
         
     | 
| 
      
 62 
     | 
    
         
            +
                    }
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                def initialize(mode)
         
     | 
| 
      
 67 
     | 
    
         
            +
                    raise ArgumentError unless MODE.include?(mode)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    @mode = mode
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                # List of supported extensions
         
     | 
| 
      
 73 
     | 
    
         
            +
                #
         
     | 
| 
      
 74 
     | 
    
         
            +
                def extensions
         
     | 
| 
      
 75 
     | 
    
         
            +
                    MODE[@mode][:extensions]
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                
         
     | 
| 
      
 79 
     | 
    
         
            +
                # List of supported mimetypes
         
     | 
| 
      
 80 
     | 
    
         
            +
                #
         
     | 
| 
      
 81 
     | 
    
         
            +
                def mimetypes
         
     | 
| 
      
 82 
     | 
    
         
            +
                    MODE[@mode][:mimetypes]
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                # (see Archiver#each)
         
     | 
| 
      
 87 
     | 
    
         
            +
                def each(file, &block)
         
     | 
| 
      
 88 
     | 
    
         
            +
                    ::Archive.read_open_filename(file) {|ar|
         
     | 
| 
      
 89 
     | 
    
         
            +
                        while a_entry = ar.next_header
         
     | 
| 
      
 90 
     | 
    
         
            +
                            next unless a_entry.regular?
         
     | 
| 
      
 91 
     | 
    
         
            +
                            $stdout.puts a_entry.pathname
         
     | 
| 
      
 92 
     | 
    
         
            +
                            block.call(a_entry.pathname, InputStream.new(ar))
         
     | 
| 
      
 93 
     | 
    
         
            +
                        end
         
     | 
| 
      
 94 
     | 
    
         
            +
                    }
         
     | 
| 
      
 95 
     | 
    
         
            +
                    self
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
            end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
            end
         
     | 
| 
      
 102 
     | 
    
         
            +
            end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,88 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # SPDX-License-Identifier: EUPL-1.2
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            begin
         
     | 
| 
      
 4 
     | 
    
         
            +
                require 'zip'
         
     | 
| 
      
 5 
     | 
    
         
            +
            rescue LoadError
         
     | 
| 
      
 6 
     | 
    
         
            +
                return
         
     | 
| 
      
 7 
     | 
    
         
            +
            end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            module Distillery
         
     | 
| 
      
 11 
     | 
    
         
            +
            class Archiver
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            # Use of rubyzip as archiver
         
     | 
| 
      
 14 
     | 
    
         
            +
            #
         
     | 
| 
      
 15 
     | 
    
         
            +
            class Zip < Archiver
         
     | 
| 
      
 16 
     | 
    
         
            +
                Archiver.add self
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                
         
     | 
| 
      
 20 
     | 
    
         
            +
                # Perform registration of the various archive format
         
     | 
| 
      
 21 
     | 
    
         
            +
                # supported by this archiver provider
         
     | 
| 
      
 22 
     | 
    
         
            +
                #
         
     | 
| 
      
 23 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 24 
     | 
    
         
            +
                #
         
     | 
| 
      
 25 
     | 
    
         
            +
                def self.registering
         
     | 
| 
      
 26 
     | 
    
         
            +
                    Archiver.register(Zip.new)
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
               
         
     | 
| 
      
 29 
     | 
    
         
            +
                
         
     | 
| 
      
 30 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
                
         
     | 
| 
      
 33 
     | 
    
         
            +
                # (see Archiver#extensions)
         
     | 
| 
      
 34 
     | 
    
         
            +
                def extensions
         
     | 
| 
      
 35 
     | 
    
         
            +
                    [ 'zip' ]
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                
         
     | 
| 
      
 39 
     | 
    
         
            +
                # (see Archiver#mimetypes)
         
     | 
| 
      
 40 
     | 
    
         
            +
                def mimetypes
         
     | 
| 
      
 41 
     | 
    
         
            +
                    [ 'application/zip' ]
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                
         
     | 
| 
      
 45 
     | 
    
         
            +
                # (see Archiver#delete!)
         
     | 
| 
      
 46 
     | 
    
         
            +
                def delete!(file, entry)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    ::Zip::File.open(file) {|zip_file|
         
     | 
| 
      
 48 
     | 
    
         
            +
                         zip_file.remove(entry) ? true : false
         
     | 
| 
      
 49 
     | 
    
         
            +
                    }
         
     | 
| 
      
 50 
     | 
    
         
            +
                rescue Errno::ENOENT
         
     | 
| 
      
 51 
     | 
    
         
            +
                    false
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                # (see Archiver#reader)
         
     | 
| 
      
 55 
     | 
    
         
            +
                def reader(file, entry, &block)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    ::Zip::File.open(file) {|zip_file|
         
     | 
| 
      
 57 
     | 
    
         
            +
                        zip_file.get_input_stream(entry) {|is|
         
     | 
| 
      
 58 
     | 
    
         
            +
                            block.call(InputStream.new(is))
         
     | 
| 
      
 59 
     | 
    
         
            +
                        }
         
     | 
| 
      
 60 
     | 
    
         
            +
                    }
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                # (see Archiver#writer)
         
     | 
| 
      
 64 
     | 
    
         
            +
                def writer(file, entry, &block)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    ::Zip::File.open(file, ::Zip::File::CREATE) {|zip_file|
         
     | 
| 
      
 66 
     | 
    
         
            +
                        zip_file.get_output_stream(entry) {|os|
         
     | 
| 
      
 67 
     | 
    
         
            +
                            block.call(OutputStream.new(os))
         
     | 
| 
      
 68 
     | 
    
         
            +
                        }
         
     | 
| 
      
 69 
     | 
    
         
            +
                    }
         
     | 
| 
      
 70 
     | 
    
         
            +
                end 
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                # (see Archiver#each) 
         
     | 
| 
      
 73 
     | 
    
         
            +
                def each(file, &block)
         
     | 
| 
      
 74 
     | 
    
         
            +
                    return to_enum(:each, file) if block.nil?
         
     | 
| 
      
 75 
     | 
    
         
            +
                    ::Zip::File.open(file) {|zip_file|
         
     | 
| 
      
 76 
     | 
    
         
            +
                        zip_file.each {|zip_entry|
         
     | 
| 
      
 77 
     | 
    
         
            +
                            next unless zip_entry.ftype == :file
         
     | 
| 
      
 78 
     | 
    
         
            +
                            block.call(zip_entry.name,
         
     | 
| 
      
 79 
     | 
    
         
            +
                                       InputStream.new(zip_entry.get_input_stream))
         
     | 
| 
      
 80 
     | 
    
         
            +
                        }
         
     | 
| 
      
 81 
     | 
    
         
            +
                    }
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
            end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            end
         
     | 
| 
      
 87 
     | 
    
         
            +
            end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     |