s3_zipper 1.0.5 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.env.test +0 -1
- data/.rubocop.yml +174 -0
- data/.rubocop_todo.yml +1569 -0
- data/Gemfile.lock +32 -19
- data/README.md +20 -1
- data/bin/console +1 -0
- data/exe/s3_zipper +13 -12
- data/lib/s3_zipper.rb +44 -26
- data/lib/s3_zipper/client.rb +13 -3
- data/lib/s3_zipper/progress.rb +38 -12
- data/lib/s3_zipper/spinner.rb +58 -0
- data/lib/s3_zipper/version.rb +3 -1
- data/s3_zipper.gemspec +13 -8
- metadata +56 -12
    
        data/Gemfile.lock
    CHANGED
    
    | @@ -1,34 +1,38 @@ | |
| 1 1 | 
             
            PATH
         | 
| 2 2 | 
             
              remote: .
         | 
| 3 3 | 
             
              specs:
         | 
| 4 | 
            -
                s3_zipper (1.0. | 
| 5 | 
            -
                  aws-sdk | 
| 4 | 
            +
                s3_zipper (1.0.9)
         | 
| 5 | 
            +
                  aws-sdk (~> 2)
         | 
| 6 | 
            +
                  concurrent-ruby (~> 1.1)
         | 
| 7 | 
            +
                  multiblock (~> 0.2.1)
         | 
| 6 8 | 
             
                  ruby-progressbar (~> 1)
         | 
| 7 9 | 
             
                  rubyzip (>= 1.0.0)
         | 
| 8 10 |  | 
| 9 11 | 
             
            GEM
         | 
| 10 12 | 
             
              remote: https://rubygems.org/
         | 
| 11 13 | 
             
              specs:
         | 
| 12 | 
            -
                 | 
| 13 | 
            -
                aws- | 
| 14 | 
            -
                aws-sdk | 
| 15 | 
            -
                  aws- | 
| 16 | 
            -
             | 
| 17 | 
            -
                  aws-sigv4 (~> 1.1)
         | 
| 18 | 
            -
                  jmespath (~> 1.0)
         | 
| 19 | 
            -
                aws-sdk-kms (1.18.0)
         | 
| 20 | 
            -
                  aws-sdk-core (~> 3, >= 3.48.2)
         | 
| 21 | 
            -
                  aws-sigv4 (~> 1.1)
         | 
| 22 | 
            -
                aws-sdk-s3 (1.36.1)
         | 
| 23 | 
            -
                  aws-sdk-core (~> 3, >= 3.48.2)
         | 
| 24 | 
            -
                  aws-sdk-kms (~> 1)
         | 
| 14 | 
            +
                ast (2.4.0)
         | 
| 15 | 
            +
                aws-eventstream (1.1.0)
         | 
| 16 | 
            +
                aws-sdk (2.11.632)
         | 
| 17 | 
            +
                  aws-sdk-resources (= 2.11.632)
         | 
| 18 | 
            +
                aws-sdk-core (2.11.632)
         | 
| 25 19 | 
             
                  aws-sigv4 (~> 1.0)
         | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 20 | 
            +
                  jmespath (~> 1.0)
         | 
| 21 | 
            +
                aws-sdk-resources (2.11.632)
         | 
| 22 | 
            +
                  aws-sdk-core (= 2.11.632)
         | 
| 23 | 
            +
                aws-sigv4 (1.2.2)
         | 
| 24 | 
            +
                  aws-eventstream (~> 1, >= 1.0.2)
         | 
| 25 | 
            +
                concurrent-ruby (1.1.5)
         | 
| 28 26 | 
             
                diff-lcs (1.3)
         | 
| 29 27 | 
             
                docile (1.3.1)
         | 
| 28 | 
            +
                jaro_winkler (1.5.2)
         | 
| 30 29 | 
             
                jmespath (1.4.0)
         | 
| 31 30 | 
             
                json (2.2.0)
         | 
| 31 | 
            +
                multiblock (0.2.1)
         | 
| 32 | 
            +
                parallel (1.17.0)
         | 
| 33 | 
            +
                parser (2.6.3.0)
         | 
| 34 | 
            +
                  ast (~> 2.4.0)
         | 
| 35 | 
            +
                rainbow (3.0.0)
         | 
| 32 36 | 
             
                rake (10.5.0)
         | 
| 33 37 | 
             
                rake-compiler (1.0.7)
         | 
| 34 38 | 
             
                  rake
         | 
| @@ -45,14 +49,22 @@ GEM | |
| 45 49 | 
             
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 46 50 | 
             
                  rspec-support (~> 3.8.0)
         | 
| 47 51 | 
             
                rspec-support (3.8.0)
         | 
| 52 | 
            +
                rubocop (0.70.0)
         | 
| 53 | 
            +
                  jaro_winkler (~> 1.5.1)
         | 
| 54 | 
            +
                  parallel (~> 1.10)
         | 
| 55 | 
            +
                  parser (>= 2.6)
         | 
| 56 | 
            +
                  rainbow (>= 2.2.2, < 4.0)
         | 
| 57 | 
            +
                  ruby-progressbar (~> 1.7)
         | 
| 58 | 
            +
                  unicode-display_width (>= 1.4.0, < 1.7)
         | 
| 48 59 | 
             
                ruby-progressbar (1.10.0)
         | 
| 49 | 
            -
                rubyzip (1.2. | 
| 60 | 
            +
                rubyzip (1.2.3)
         | 
| 50 61 | 
             
                simplecov (0.16.1)
         | 
| 51 62 | 
             
                  docile (~> 1.1)
         | 
| 52 63 | 
             
                  json (>= 1.8, < 3)
         | 
| 53 64 | 
             
                  simplecov-html (~> 0.10.0)
         | 
| 54 65 | 
             
                simplecov-html (0.10.2)
         | 
| 55 66 | 
             
                thor (0.20.3)
         | 
| 67 | 
            +
                unicode-display_width (1.6.0)
         | 
| 56 68 |  | 
| 57 69 | 
             
            PLATFORMS
         | 
| 58 70 | 
             
              ruby
         | 
| @@ -62,9 +74,10 @@ DEPENDENCIES | |
| 62 74 | 
             
              rake (~> 10.0)
         | 
| 63 75 | 
             
              rake-compiler
         | 
| 64 76 | 
             
              rspec (~> 3.0)
         | 
| 77 | 
            +
              rubocop (~> 0.70.0)
         | 
| 65 78 | 
             
              s3_zipper!
         | 
| 66 79 | 
             
              simplecov
         | 
| 67 80 | 
             
              thor
         | 
| 68 81 |  | 
| 69 82 | 
             
            BUNDLED WITH
         | 
| 70 | 
            -
               2. | 
| 83 | 
            +
               2.2.12
         | 
    
        data/README.md
    CHANGED
    
    | @@ -46,6 +46,25 @@ zipper.zip_to_s3(keys) | |
| 46 46 | 
             
            # }
         | 
| 47 47 | 
             
            ```
         | 
| 48 48 |  | 
| 49 | 
            +
            ### Event Handling
         | 
| 50 | 
            +
            ```ruby
         | 
| 51 | 
            +
            keys = ["documents/files/790/306/985/original/background-10.jpg", "documents/files/790/307/076/original/background-10.jpg"]
         | 
| 52 | 
            +
            zipper.zip_to_s3 keys do
         | 
| 53 | 
            +
              on.start { puts 'Starting to zip' }
         | 
| 54 | 
            +
              on.progress { |progress| puts progress.percentage }
         | 
| 55 | 
            +
              on.finish { puts 'Finished zipping' }
         | 
| 56 | 
            +
              on.upload { puts 'Upload complete' }
         | 
| 57 | 
            +
            end
         | 
| 58 | 
            +
            # {
         | 
| 59 | 
            +
            #   :key=>"3dc29e9ba0a069eb5d0783f07b12e1b3.zip", 
         | 
| 60 | 
            +
            #   :url => "https://bucket_name.s3.us-west-2.amazonaws.com/35b6f0e2ee91aa0e3c0640c7a4b2b7db.zip" 
         | 
| 61 | 
            +
            #   :zipped=>["documents/files/790/306/985/original/background-10.jpg", "documents/files/790/307/076/original/background-10.jpg"], 
         | 
| 62 | 
            +
            #   :failed=>[]
         | 
| 63 | 
            +
            # }
         | 
| 64 | 
            +
            ```
         | 
| 65 | 
            +
             | 
| 66 | 
            +
             | 
| 67 | 
            +
             | 
| 49 68 | 
             
            ## Development
         | 
| 50 69 |  | 
| 51 70 | 
             
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         | 
| @@ -54,7 +73,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To | |
| 54 73 |  | 
| 55 74 | 
             
            ## Contributing
         | 
| 56 75 |  | 
| 57 | 
            -
            Bug reports and pull requests are welcome on GitHub at https://github.com/ | 
| 76 | 
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/capshareinc/s3_zipper. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
         | 
| 58 77 |  | 
| 59 78 | 
             
            ## License
         | 
| 60 79 |  | 
    
        data/bin/console
    CHANGED
    
    
    
        data/exe/s3_zipper
    CHANGED
    
    | @@ -1,24 +1,25 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 2 3 |  | 
| 3 4 | 
             
            require "s3_zipper"
         | 
| 4 | 
            -
            require  | 
| 5 | 
            -
            require  | 
| 5 | 
            +
            require "thor"
         | 
| 6 | 
            +
            require "awesome_print"
         | 
| 6 7 | 
             
            class CLI < Thor
         | 
| 7 | 
            -
              desc  | 
| 8 | 
            -
              method_option :filename, type: :string, aliases:  | 
| 9 | 
            -
              method_option :bucket, type: :string, default: ENV[ | 
| 8 | 
            +
              desc "local_file FILES", "zip files from s3 to a local file"
         | 
| 9 | 
            +
              method_option :filename, type: :string, aliases: "f", desc: "Name of the created zip archive"
         | 
| 10 | 
            +
              method_option :bucket, type: :string, default: ENV["AWS_BUCKET"], required: !ENV["AWS_BUCKET"].nil?, aliases: "b", desc: "Name of the bucket the files are in"
         | 
| 10 11 |  | 
| 11 | 
            -
              def local_file | 
| 12 | 
            +
              def local_file *files
         | 
| 12 13 | 
             
                S3Zipper.new(options[:bucket]).zip_to_local_file(files, file: options[:filename] || SecureRandom.hex)
         | 
| 13 14 | 
             
              end
         | 
| 14 15 |  | 
| 15 | 
            -
              desc  | 
| 16 | 
            -
              method_option :filename, type: :string, aliases:  | 
| 17 | 
            -
              method_option :path, type: :string, aliases:  | 
| 18 | 
            -
              method_option :bucket, type: :string, default: ENV[ | 
| 16 | 
            +
              desc "s3 FILES", "zip files from s3 to s3"
         | 
| 17 | 
            +
              method_option :filename, type: :string, aliases: "f", desc: "Name of the created zip archive"
         | 
| 18 | 
            +
              method_option :path, type: :string, aliases: "p", desc: "Path to the file in s3"
         | 
| 19 | 
            +
              method_option :bucket, type: :string, default: ENV["AWS_BUCKET"], required: !ENV["AWS_BUCKET"].nil?, aliases: "b", desc: "Name of the bucket the files are in"
         | 
| 19 20 |  | 
| 20 | 
            -
              def s3 | 
| 21 | 
            +
              def s3 *files
         | 
| 21 22 | 
             
                S3Zipper.new(options[:bucket]).zip_to_s3(files, filename: options[:filename] || SecureRandom.hex, path: options[:path])
         | 
| 22 23 | 
             
              end
         | 
| 23 24 | 
             
            end
         | 
| 24 | 
            -
            CLI.start(ARGV)
         | 
| 25 | 
            +
            CLI.start(ARGV)
         | 
    
        data/lib/s3_zipper.rb
    CHANGED
    
    | @@ -1,37 +1,46 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require "s3_zipper/version"
         | 
| 2 | 
            -
            require  | 
| 4 | 
            +
            require "s3_zipper/progress"
         | 
| 5 | 
            +
            require "s3_zipper/spinner"
         | 
| 3 6 | 
             
            require "s3_zipper/client"
         | 
| 4 7 | 
             
            require "zip"
         | 
| 8 | 
            +
            require "multiblock"
         | 
| 5 9 |  | 
| 6 10 | 
             
            class S3Zipper
         | 
| 7 | 
            -
              attr_accessor :client, :options, :progress
         | 
| 11 | 
            +
              attr_accessor :client, :options, :progress, :zip_client, :wrapper
         | 
| 8 12 |  | 
| 9 13 | 
             
              # @param [String] bucket - bucket that files exist in
         | 
| 10 14 | 
             
              # @param [Hash] options - options for zipper
         | 
| 11 15 | 
             
              # @option options [Boolean] :progress - toggles progress tracking
         | 
| 12 16 | 
             
              # @return [S3Zipper]
         | 
| 13 17 | 
             
              def initialize bucket, options = {}
         | 
| 14 | 
            -
                @options | 
| 15 | 
            -
                @ | 
| 16 | 
            -
                @progress | 
| 18 | 
            +
                @options    = options
         | 
| 19 | 
            +
                @wrapper    = Multiblock.wrapper
         | 
| 20 | 
            +
                @progress   = Progress.new(enabled: options[:progress], format: "%e %c/%C %t", total: nil, length: 80, autofinish: false)
         | 
| 21 | 
            +
                @client     = Client.new(bucket, options)
         | 
| 22 | 
            +
                @zip_client = Client.new(options[:zip_bucket], options) if options[:zip_bucket]
         | 
| 23 | 
            +
                @zip_client ||= @client
         | 
| 17 24 | 
             
              end
         | 
| 18 25 |  | 
| 19 26 | 
             
              # Zips files from s3 to a local zip
         | 
| 20 27 | 
             
              # @param [Array] keys - Array of s3 keys to zip
         | 
| 21 28 | 
             
              # @param [String, File] file - Filename or file object for the zip, defaults to a random string
         | 
| 22 29 | 
             
              # @return [Hash]
         | 
| 23 | 
            -
              def zip_to_local_file | 
| 24 | 
            -
                 | 
| 25 | 
            -
                 | 
| 30 | 
            +
              def zip_to_local_file keys, file: SecureRandom.hex
         | 
| 31 | 
            +
                yield(wrapper) if block_given?
         | 
| 32 | 
            +
                file = file.is_a?(File) ? file : File.open("#{file}.zip", "w")
         | 
| 33 | 
            +
                zip(keys, file.path)
         | 
| 26 34 | 
             
              end
         | 
| 27 35 |  | 
| 28 36 | 
             
              # Zips files from s3 to a temporary zip
         | 
| 29 37 | 
             
              # @param [Array] keys - Array of s3 keys to zip
         | 
| 30 38 | 
             
              # @param [String, File] filename - Name of file, defaults to a random string
         | 
| 31 39 | 
             
              # @return [Hash]
         | 
| 32 | 
            -
              def zip_to_tempfile | 
| 33 | 
            -
                 | 
| 34 | 
            -
                 | 
| 40 | 
            +
              def zip_to_tempfile keys, filename: SecureRandom.hex, cleanup: false
         | 
| 41 | 
            +
                yield(wrapper) if block_given?
         | 
| 42 | 
            +
                zipfile = Tempfile.new([filename, ".zip"])
         | 
| 43 | 
            +
                result  = zip(keys, zipfile.path)
         | 
| 35 44 | 
             
                zipfile.unlink if cleanup
         | 
| 36 45 | 
             
                result
         | 
| 37 46 | 
             
              end
         | 
| @@ -41,36 +50,45 @@ class S3Zipper | |
| 41 50 | 
             
              # @param [String, File] filename - Name of file, defaults to a random string
         | 
| 42 51 | 
             
              # @param [String] path - path for file in s3
         | 
| 43 52 | 
             
              # @return [Hash]
         | 
| 44 | 
            -
              def zip_to_s3 keys, filename: SecureRandom.hex, path: nil, s3_options: {} | 
| 45 | 
            -
                 | 
| 53 | 
            +
              def zip_to_s3 keys, filename: SecureRandom.hex, path: nil, s3_options: {}
         | 
| 54 | 
            +
                yield(wrapper) if block_given?
         | 
| 46 55 | 
             
                filename = "#{path ? "#{path}/" : ''}#{filename}.zip"
         | 
| 47 | 
            -
                result   = zip_to_tempfile(keys, filename: filename, cleanup: false | 
| 48 | 
            -
                 | 
| 49 | 
            -
                client.upload(result.delete(:filename), filename, options: s3_options)
         | 
| 50 | 
            -
                progress.finish(title: "Uploaded zip to #{filename}")
         | 
| 56 | 
            +
                result   = zip_to_tempfile(keys, filename: filename, cleanup: false)
         | 
| 57 | 
            +
                zip_client.upload(result.delete(:filename), filename, options: s3_options)
         | 
| 51 58 | 
             
                result[:key] = filename
         | 
| 52 | 
            -
                result[:url] =  | 
| 59 | 
            +
                result[:url] = zip_client.get_url(result[:key])
         | 
| 60 | 
            +
                wrapper.call(:upload, result)
         | 
| 53 61 | 
             
                result
         | 
| 54 62 | 
             
              end
         | 
| 55 63 |  | 
| 56 64 | 
             
              private
         | 
| 57 65 |  | 
| 66 | 
            +
              def add_to_zip zipfile, filename, file, n = 0
         | 
| 67 | 
            +
                existing_file = zipfile.find_entry(filename)
         | 
| 68 | 
            +
                if existing_file
         | 
| 69 | 
            +
                  filename = "#{File.basename(filename, ".*").split('(').first}(#{n})#{File.extname(filename)}"
         | 
| 70 | 
            +
                  add_to_zip(zipfile, filename, file, n + 1)
         | 
| 71 | 
            +
                else
         | 
| 72 | 
            +
                  zipfile.add(filename, file.path)
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
             | 
| 58 76 | 
             
              # @param [Array] keys - Array of s3 keys to zip
         | 
| 59 77 | 
             
              # @param [String] path - path to zip
         | 
| 60 78 | 
             
              # @yield [progress]
         | 
| 61 79 | 
             
              # @return [Hash]
         | 
| 62 | 
            -
              def zip | 
| 63 | 
            -
                 | 
| 64 | 
            -
                total += keys.size
         | 
| 65 | 
            -
                progress.update_attrs total: total, title: "Zipping Keys to #{path}"
         | 
| 80 | 
            +
              def zip keys, path
         | 
| 81 | 
            +
                progress.reset total: keys.size, title: "Zipping Keys to #{path}"
         | 
| 66 82 | 
             
                Zip::File.open(path, Zip::File::CREATE) do |zipfile|
         | 
| 83 | 
            +
                  wrapper.call(:start, zipfile)
         | 
| 67 84 | 
             
                  @failed, @successful = client.download_keys keys do |file, key|
         | 
| 68 | 
            -
                    progress.increment
         | 
| 69 | 
            -
                     | 
| 70 | 
            -
                    yield(zipfile, progress) if block_given?
         | 
| 85 | 
            +
                    progress.increment title: "Zipping #{key} to #{path}"
         | 
| 86 | 
            +
                    wrapper.call(:progress, progress)
         | 
| 71 87 | 
             
                    next if file.nil?
         | 
| 72 | 
            -
                    zipfile | 
| 88 | 
            +
                    add_to_zip(zipfile, File.basename(key), file)
         | 
| 73 89 | 
             
                  end
         | 
| 90 | 
            +
                  progress.finish(title: "Zipped keys to #{path}")
         | 
| 91 | 
            +
                  wrapper.call(:finish, zipfile)
         | 
| 74 92 | 
             
                end
         | 
| 75 93 | 
             
                @successful.each { |_, temp| temp.unlink }
         | 
| 76 94 | 
             
                {
         | 
    
        data/lib/s3_zipper/client.rb
    CHANGED
    
    | @@ -1,4 +1,6 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "aws-sdk"
         | 
| 2 4 |  | 
| 3 5 | 
             
            class S3Zipper
         | 
| 4 6 | 
             
              class Client
         | 
| @@ -42,18 +44,26 @@ class S3Zipper | |
| 42 44 | 
             
                  temp.binmode
         | 
| 43 45 | 
             
                  temp = download_to_file key, temp
         | 
| 44 46 | 
             
                  return if temp.nil?
         | 
| 47 | 
            +
             | 
| 45 48 | 
             
                  yield(temp) if block_given?
         | 
| 46 49 | 
             
                  temp
         | 
| 47 50 | 
             
                ensure
         | 
| 48 51 | 
             
                  temp&.unlink if cleanup
         | 
| 49 52 | 
             
                end
         | 
| 50 53 |  | 
| 51 | 
            -
                def get_url | 
| 54 | 
            +
                def get_url key
         | 
| 52 55 | 
             
                  resource.bucket(bucket_name).object(key).public_url
         | 
| 53 56 | 
             
                end
         | 
| 54 57 |  | 
| 55 58 | 
             
                def upload local_path, repo_path, options: {}
         | 
| 56 | 
            -
                   | 
| 59 | 
            +
                  spinner = Spinner.new(
         | 
| 60 | 
            +
                    enabled: options[:progress],
         | 
| 61 | 
            +
                    title:   "Uploading zip to #{bucket_name}/#{repo_path}",
         | 
| 62 | 
            +
                  )
         | 
| 63 | 
            +
                  spinner.start
         | 
| 64 | 
            +
                  object = client.put_object(options.merge!(bucket: bucket_name, key: repo_path, body: File.open(local_path).read))
         | 
| 65 | 
            +
                  spinner.finish title: "Uploaded zip to #{bucket_name}/#{repo_path}"
         | 
| 66 | 
            +
                  object
         | 
| 57 67 | 
             
                end
         | 
| 58 68 | 
             
              end
         | 
| 59 69 | 
             
            end
         | 
    
        data/lib/s3_zipper/progress.rb
    CHANGED
    
    | @@ -1,38 +1,61 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "ruby-progressbar"
         | 
| 2 4 | 
             
            class Progress
         | 
| 5 | 
            +
             | 
| 3 6 | 
             
              def initialize options = {}
         | 
| 4 7 | 
             
                return unless options[:enabled] || true
         | 
| 8 | 
            +
             | 
| 5 9 | 
             
                @options      = options
         | 
| 6 10 | 
             
                @format       = options[:format]
         | 
| 7 11 | 
             
                @progress_bar = ProgressBar.create(@options)
         | 
| 8 12 | 
             
              end
         | 
| 9 13 |  | 
| 10 | 
            -
              def reset | 
| 14 | 
            +
              def reset title: nil, total: nil, format: nil
         | 
| 15 | 
            +
                return unless @progress_bar
         | 
| 16 | 
            +
             | 
| 11 17 | 
             
                @progress_bar.progress = 0
         | 
| 12 | 
            -
                @progress_bar.title    = title
         | 
| 13 | 
            -
                @progress_bar.total    = total
         | 
| 14 | 
            -
                @progress_bar.format   = format
         | 
| 18 | 
            +
                @progress_bar.title    = title if title
         | 
| 19 | 
            +
                @progress_bar.total    = total if total
         | 
| 20 | 
            +
                @progress_bar.format   = format if format
         | 
| 15 21 | 
             
                refresh
         | 
| 16 22 | 
             
              end
         | 
| 17 23 |  | 
| 24 | 
            +
              def spin
         | 
| 25 | 
            +
                until @progress_bar.finished?
         | 
| 26 | 
            +
                  increment
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 18 30 | 
             
              def total
         | 
| 19 | 
            -
                @progress_bar | 
| 31 | 
            +
                return unless @progress_bar
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                @progress_bar.total
         | 
| 20 34 | 
             
              end
         | 
| 21 35 |  | 
| 22 36 | 
             
              def percentage
         | 
| 23 | 
            -
                @progress_bar | 
| 37 | 
            +
                return unless @progress_bar
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                @progress_bar.to_h["percentage"]
         | 
| 24 40 | 
             
              end
         | 
| 25 41 |  | 
| 26 42 | 
             
              def refresh
         | 
| 27 | 
            -
                @progress_bar | 
| 43 | 
            +
                return unless @progress_bar
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                @progress_bar.refresh
         | 
| 28 46 | 
             
              end
         | 
| 29 47 |  | 
| 30 48 | 
             
              def progress
         | 
| 31 | 
            -
                @progress_bar | 
| 49 | 
            +
                return unless @progress_bar
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                @progress_bar.progress
         | 
| 32 52 | 
             
              end
         | 
| 33 53 |  | 
| 34 | 
            -
              def increment
         | 
| 35 | 
            -
                @progress_bar | 
| 54 | 
            +
              def increment attrs = {}
         | 
| 55 | 
            +
                return unless @progress_bar
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                @progress_bar.increment
         | 
| 58 | 
            +
                update_attrs(attrs) unless attrs.empty?
         | 
| 36 59 | 
             
              end
         | 
| 37 60 |  | 
| 38 61 | 
             
              def update_attrs attrs
         | 
| @@ -41,11 +64,13 @@ class Progress | |
| 41 64 |  | 
| 42 65 | 
             
              def update attr, value
         | 
| 43 66 | 
             
                return unless @progress_bar
         | 
| 67 | 
            +
             | 
| 44 68 | 
             
                @progress_bar.send("#{attr}=", value)
         | 
| 45 69 | 
             
              end
         | 
| 46 70 |  | 
| 47 71 | 
             
              def finish title: nil, format: nil
         | 
| 48 72 | 
             
                return unless @progress_bar
         | 
| 73 | 
            +
             | 
| 49 74 | 
             
                @progress_bar.title  = title if title
         | 
| 50 75 | 
             
                @progress_bar.format = format if format
         | 
| 51 76 | 
             
                @progress_bar.finish
         | 
| @@ -57,6 +82,7 @@ class Progress | |
| 57 82 |  | 
| 58 83 | 
             
              def get_attr attr
         | 
| 59 84 | 
             
                return unless @progress_bar
         | 
| 85 | 
            +
             | 
| 60 86 | 
             
                @progress_bar.send(attr)
         | 
| 61 87 | 
             
              end
         | 
| 62 | 
            -
            end
         | 
| 88 | 
            +
            end
         | 
| @@ -0,0 +1,58 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "ruby-progressbar"
         | 
| 4 | 
            +
            require "concurrent-ruby"
         | 
| 5 | 
            +
            class S3Zipper
         | 
| 6 | 
            +
              class Spinner
         | 
| 7 | 
            +
                include Concurrent::Async
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def initialize title: "", enabled: true, steps: %w[▸▹▹▹▹▹ ▹▸▹▹▹▹ ▹▹▸▹▹▹ ▹▹▹▸▹▹ ▹▹▹▹▸▹ ▹▹▹▹▹▸ ▹▹▹▹▹]
         | 
| 10 | 
            +
                  return unless enabled || true
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  @progress_bar = ProgressBar.create(
         | 
| 13 | 
            +
                    format:                           "[%B] %t",
         | 
| 14 | 
            +
                    total:                            nil,
         | 
| 15 | 
            +
                    length:                           100,
         | 
| 16 | 
            +
                    title:                            title,
         | 
| 17 | 
            +
                    autofinish:                       false,
         | 
| 18 | 
            +
                    unknown_progress_animation_steps: steps,
         | 
| 19 | 
            +
                  )
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def reset title: nil, total: nil, format: nil
         | 
| 23 | 
            +
                  return unless @progress_bar
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  @progress_bar.progress = 0
         | 
| 26 | 
            +
                  @progress_bar.title    = title if title
         | 
| 27 | 
            +
                  @progress_bar.total    = total if total
         | 
| 28 | 
            +
                  @progress_bar.format   = format if format
         | 
| 29 | 
            +
                  refresh
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def start
         | 
| 33 | 
            +
                  async.spin
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def spin
         | 
| 37 | 
            +
                  return unless @progress_bar
         | 
| 38 | 
            +
                  until @progress_bar.finished?
         | 
| 39 | 
            +
                    increment
         | 
| 40 | 
            +
                    sleep(2)
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def increment
         | 
| 45 | 
            +
                  return unless @progress_bar
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  @progress_bar.increment
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def finish title: nil
         | 
| 51 | 
            +
                  return unless @progress_bar
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  @progress_bar.title  = title if title
         | 
| 54 | 
            +
                  @progress_bar.format = "[✔] %t"
         | 
| 55 | 
            +
                  @progress_bar.finish
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
            end
         |