binaryen 1.1.6.6 → 1.1.6.8
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/lib/binaryen/command.rb +71 -94
- data/lib/binaryen/error.rb +1 -0
- data/lib/binaryen/version.rb +1 -1
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 4217d4168d453c8e5316e9c66929d5e09057ec356dc6f80802c41521de6fd612
         | 
| 4 | 
            +
              data.tar.gz: 2cb4b068c0456d72dcc55cf0d945a5357df0d3ad8c82166fca8a57dcd2908ec4
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 9e3fd947316b466a8d592014bc57b1c34148da5b3042e0630b2bc5f56e54c287ab4c6416e78c1ef392e88429cbbcba0c0c3549bdd8b99d7068972c1adeb0c698
         | 
| 7 | 
            +
              data.tar.gz: 2cdfe8e57ab692f16e911e7a819cb6cfecbf9b31027a04c8863eb919fd952cb6d92832d3884768cf05704507c7c408bcfb19eed3c47b90dfcbb6f1e7eaefc679
         | 
    
        data/lib/binaryen/command.rb
    CHANGED
    
    | @@ -1,131 +1,108 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require "English"
         | 
| 4 | 
            -
            require "shellwords"
         | 
| 5 | 
            -
            require "timeout"
         | 
| 6 3 | 
             
            require "posix/spawn"
         | 
| 4 | 
            +
            require "timeout"
         | 
| 5 | 
            +
            require "tempfile"
         | 
| 7 6 |  | 
| 8 7 | 
             
            module Binaryen
         | 
| 9 | 
            -
              # Wrapper around a binaryen executable command with a timeout and streaming IO.
         | 
| 10 | 
            -
              #
         | 
| 11 | 
            -
              # @example Running wasm-opt
         | 
| 12 | 
            -
              #
         | 
| 13 | 
            -
              #   ```ruby
         | 
| 14 | 
            -
              #   command = Binaryen::Command.new("wasm-opt", timeout: 10)
         | 
| 15 | 
            -
              #   optimized_wasm = command.run("-O4", stdin: "(module)")
         | 
| 16 | 
            -
              #   ```
         | 
| 17 8 | 
             
              class Command
         | 
| 18 9 | 
             
                include POSIX::Spawn
         | 
| 19 | 
            -
             | 
| 10 | 
            +
                DEFAULT_MAX_OUTPUT_SIZE = 256 * 1024 * 1024
         | 
| 11 | 
            +
                DEFAULT_TIMEOUT = 10
         | 
| 20 12 | 
             
                DEFAULT_ARGS_FOR_COMMAND = {
         | 
| 21 13 | 
             
                  "wasm-opt" => ["--output=-"],
         | 
| 22 14 | 
             
                }.freeze
         | 
| 23 15 |  | 
| 24 | 
            -
                 | 
| 25 | 
            -
                  def initialize(end_time:, pid:)
         | 
| 26 | 
            -
                    @end_time = end_time
         | 
| 27 | 
            -
                    @pid = pid
         | 
| 28 | 
            -
                  end
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                  def check!
         | 
| 31 | 
            -
                    now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
         | 
| 32 | 
            -
                    if now >= @end_time
         | 
| 33 | 
            -
                      Process.kill("TERM", @pid)
         | 
| 34 | 
            -
                      raise Timeout::Error, "Command timed out"
         | 
| 35 | 
            -
                    end
         | 
| 36 | 
            -
                    remaining_time = @end_time - now
         | 
| 37 | 
            -
                    remaining_time
         | 
| 38 | 
            -
                  end
         | 
| 39 | 
            -
                end
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                def initialize(cmd, timeout: 10, ignore_missing: false)
         | 
| 16 | 
            +
                def initialize(cmd, timeout: DEFAULT_TIMEOUT, max_output_size: DEFAULT_MAX_OUTPUT_SIZE, ignore_missing: false)
         | 
| 42 17 | 
             
                  @cmd = command_path(cmd, ignore_missing) || raise(ArgumentError, "command not found: #{cmd}")
         | 
| 43 18 | 
             
                  @timeout = timeout
         | 
| 44 19 | 
             
                  @default_args = DEFAULT_ARGS_FOR_COMMAND.fetch(cmd, [])
         | 
| 20 | 
            +
                  @max_output_size = max_output_size
         | 
| 45 21 | 
             
                end
         | 
| 46 22 |  | 
| 47 23 | 
             
                def run(*arguments, stdin: nil, stderr: nil)
         | 
| 48 | 
            -
                   | 
| 49 | 
            -
                  command = build_command(*arguments)
         | 
| 50 | 
            -
                  pid, iwr, ord, erd = popen4(*command)
         | 
| 51 | 
            -
                  timeout_checker = TimeoutChecker.new(end_time: end_time, pid: pid)
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                  write_to_pipe(iwr, stdin, timeout_checker, pid) if stdin
         | 
| 24 | 
            +
                  args = [@cmd] + arguments + @default_args
         | 
| 54 25 |  | 
| 55 | 
            -
                  if  | 
| 56 | 
            -
                     | 
| 57 | 
            -
             | 
| 26 | 
            +
                  if stdin
         | 
| 27 | 
            +
                    with_stdin_tempfile(stdin) { |path| spawn_command(*args, path, stderr: stderr) }
         | 
| 28 | 
            +
                  else
         | 
| 29 | 
            +
                    spawn_command(*args, stderr: stderr)
         | 
| 58 30 | 
             
                  end
         | 
| 59 | 
            -
                  output = read_from_pipe(ord, timeout_checker)
         | 
| 60 | 
            -
                  wait_or_kill(pid, timeout_checker)
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                  output
         | 
| 63 31 | 
             
                end
         | 
| 64 32 |  | 
| 65 33 | 
             
                private
         | 
| 66 34 |  | 
| 67 | 
            -
                def  | 
| 68 | 
            -
                   | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
                     | 
| 73 | 
            -
             | 
| 74 | 
            -
                    next unless IO.select(nil, [pipe], nil, remaining_time)
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                    begin
         | 
| 77 | 
            -
                      written = pipe.write_nonblock(stdin.byteslice(offset, length), exception: false)
         | 
| 78 | 
            -
                      offset += written if written.is_a?(Integer)
         | 
| 79 | 
            -
                    rescue Errno::EPIPE
         | 
| 80 | 
            -
                      wait_or_kill(pid, timeout_checker, pid)
         | 
| 81 | 
            -
                    end
         | 
| 35 | 
            +
                def with_stdin_tempfile(content)
         | 
| 36 | 
            +
                  Tempfile.open("binaryen-stdin") do |f|
         | 
| 37 | 
            +
                    f.binmode
         | 
| 38 | 
            +
                    f.write(content)
         | 
| 39 | 
            +
                    f.close
         | 
| 40 | 
            +
                    yield f.path
         | 
| 82 41 | 
             
                  end
         | 
| 83 | 
            -
                ensure
         | 
| 84 | 
            -
                  pipe.close_write if close_write
         | 
| 85 42 | 
             
                end
         | 
| 86 43 |  | 
| 87 | 
            -
                def  | 
| 88 | 
            -
                   | 
| 89 | 
            -
             | 
| 90 | 
            -
                  while (result = pipe.read_nonblock(8192, exception: false))
         | 
| 91 | 
            -
                    remaining_time = timeout_checker.check!
         | 
| 92 | 
            -
             | 
| 93 | 
            -
                    case result
         | 
| 94 | 
            -
                    when :wait_readable
         | 
| 95 | 
            -
                      IO.select([pipe], nil, nil, remaining_time)
         | 
| 96 | 
            -
                    when nil
         | 
| 97 | 
            -
                      break
         | 
| 98 | 
            -
                    else
         | 
| 99 | 
            -
                      output << result
         | 
| 100 | 
            -
                    end
         | 
| 101 | 
            -
                  end
         | 
| 102 | 
            -
             | 
| 103 | 
            -
                  output
         | 
| 104 | 
            -
                ensure
         | 
| 105 | 
            -
                  pipe.close_read if close_read
         | 
| 44 | 
            +
                def command_path(cmd, ignore_missing)
         | 
| 45 | 
            +
                  Dir[File.join(Binaryen.bindir, cmd)].first || (ignore_missing && cmd)
         | 
| 106 46 | 
             
                end
         | 
| 107 47 |  | 
| 108 | 
            -
                def  | 
| 109 | 
            -
                   | 
| 110 | 
            -
             | 
| 48 | 
            +
                def spawn_command(*args, stderr: nil)
         | 
| 49 | 
            +
                  out = "".b
         | 
| 50 | 
            +
                  data_buffer = "".b
         | 
| 51 | 
            +
                  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
         | 
| 52 | 
            +
                  pid, stdin, stdout, stderr_stream = popen4(*args)
         | 
| 53 | 
            +
                  stdin.close
         | 
| 54 | 
            +
                  @pid = pid
         | 
| 55 | 
            +
                  readers = [stdout, stderr_stream]
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  while readers.any?
         | 
| 58 | 
            +
                    elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
         | 
| 59 | 
            +
                    remaining_time = @timeout - elapsed_time
         | 
| 60 | 
            +
                    ready = IO.select(readers, nil, nil, remaining_time)
         | 
| 61 | 
            +
                    raise Timeout::Error, "command timed out after #{@timeout} seconds" if ready.nil?
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    ready[0].each do |io|
         | 
| 64 | 
            +
                      max_amount_to_read = @max_output_size - out.bytesize + 1
         | 
| 65 | 
            +
                      data = io.read_nonblock(max_amount_to_read, data_buffer, exception: false)
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                      if data == :wait_readable
         | 
| 68 | 
            +
                        # If the IO object is not ready for reading, read_nonblock returns :wait_readable.
         | 
| 69 | 
            +
                        # This isn't an error, but a notification.
         | 
| 70 | 
            +
                        next
         | 
| 71 | 
            +
                      elsif data.nil?
         | 
| 72 | 
            +
                        # At EOF, read_nonblock returns nil instead of raising EOFError.
         | 
| 73 | 
            +
                        readers.delete(io)
         | 
| 74 | 
            +
                      elsif io == stdout
         | 
| 75 | 
            +
                        out << data_buffer
         | 
| 76 | 
            +
                      elsif io == stderr_stream && stderr
         | 
| 77 | 
            +
                        stderr << data_buffer
         | 
| 78 | 
            +
                      end
         | 
| 79 | 
            +
                    rescue Errno::EPIPE, Errno::EINTR
         | 
| 80 | 
            +
                      # Handle EPIPE and EINTR errors
         | 
| 81 | 
            +
                      readers.delete(io)
         | 
| 82 | 
            +
                    end
         | 
| 111 83 |  | 
| 112 | 
            -
                    if  | 
| 113 | 
            -
                       | 
| 114 | 
            -
             | 
| 84 | 
            +
                    if out.bytesize > @max_output_size
         | 
| 85 | 
            +
                      Process.kill("TERM", @pid)
         | 
| 86 | 
            +
                      raise Binaryen::MaximumOutputExceeded, "maximum output size exceeded (#{@max_output_size} bytes)"
         | 
| 87 | 
            +
                    end
         | 
| 115 88 |  | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
                       | 
| 89 | 
            +
                    if remaining_time < 0
         | 
| 90 | 
            +
                      Process.kill("TERM", @pid)
         | 
| 91 | 
            +
                      raise Timeout::Error, "command timed out after #{@timeout} seconds"
         | 
| 119 92 | 
             
                    end
         | 
| 120 93 | 
             
                  end
         | 
| 121 | 
            -
                end
         | 
| 122 94 |  | 
| 123 | 
            -
             | 
| 124 | 
            -
                  [@cmd] + arguments + @default_args
         | 
| 125 | 
            -
                end
         | 
| 95 | 
            +
                  _, status = Process.waitpid2(pid, Process::WUNTRACED)
         | 
| 126 96 |  | 
| 127 | 
            -
             | 
| 128 | 
            -
             | 
| 97 | 
            +
                  raise Binaryen::NonZeroExitStatus, "command exited with status #{status.exitstatus}" unless status.success?
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  out
         | 
| 100 | 
            +
                ensure
         | 
| 101 | 
            +
                  [stdin, stdout, stderr_stream].each do |io|
         | 
| 102 | 
            +
                    io.close
         | 
| 103 | 
            +
                  rescue
         | 
| 104 | 
            +
                    nil
         | 
| 105 | 
            +
                  end
         | 
| 129 106 | 
             
                end
         | 
| 130 107 | 
             
              end
         | 
| 131 108 | 
             
            end
         | 
    
        data/lib/binaryen/error.rb
    CHANGED
    
    
    
        data/lib/binaryen/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: binaryen
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1.1.6. | 
| 4 | 
            +
              version: 1.1.6.8
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Shopify Inc.
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023-12- | 
| 11 | 
            +
            date: 2023-12-19 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: posix-spawn
         |