wardite 0.6.1 → 0.8.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/Steepfile +1 -0
- data/exe/wardite +3 -25
- data/lib/wardite/cli/cli.rb +135 -0
- data/lib/wardite/value.rb +1 -1
- data/lib/wardite/version.rb +1 -1
- data/lib/wardite/wasi/consts.rb +7 -0
- data/lib/wardite/wasi/dirent_cache.rb +87 -0
- data/lib/wardite/wasi/preopens.rb +17 -0
- data/lib/wardite/wasi.rb +457 -17
- data/lib/wardite.rb +8 -1
- data/rbs_collection.lock.yaml +204 -0
- data/rbs_collection.yaml +18 -0
- data/sig/bundler.rbs +3 -0
- data/sig/generated/wardite/cli/cli.rbs +52 -0
- data/sig/generated/wardite/wasi/consts.rbs +10 -0
- data/sig/generated/wardite/wasi/dirent_cache.rbs +42 -0
- data/sig/generated/wardite/wasi/preopens.rbs +15 -0
- data/sig/generated/wardite/wasi.rbs +102 -2
- data/sig/generated/wardite.rbs +5 -1
- metadata +11 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 20aa59cedbb81d21c2681737929bb7f29fcf70cd189ca5d0de1ff538fca57782
         | 
| 4 | 
            +
              data.tar.gz: fed9168236c3d23e377d38e2a6bf175336def008268aa5910215667ff3fac750
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: '098a4d2d2c25221667307bdf49fa207f682dd0f53e9ee33700cf18790961ce0ea627ed3f8ff7292a4cf55d70bf0c6068ed0b4b03502ec95aedd511c547dac7a0'
         | 
| 7 | 
            +
              data.tar.gz: 9e1b69ba3cea02e033892ad4bf3fafc456d96d0f4741e8b0a9b6c55d2285cbb7d29fc0f0b2e71b1b35812c905b6281d1c4713c7b9215c5f99b42d94c88a6295b
         | 
    
        data/Steepfile
    CHANGED
    
    
    
        data/exe/wardite
    CHANGED
    
    | @@ -1,29 +1,7 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 2 |  | 
| 3 3 | 
             
            require "wardite"
         | 
| 4 | 
            -
             | 
| 4 | 
            +
            require "wardite/cli/cli"
         | 
| 5 5 |  | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
            if instance.runtime.respond_to?(:_start) # assumed WASI
         | 
| 9 | 
            -
              argv = ARGV[1..-1] || []
         | 
| 10 | 
            -
              instance.wasi.argv = ["wardite"] + argv
         | 
| 11 | 
            -
              Bundler.with_original_env do
         | 
| 12 | 
            -
                # instance.store.memories[0].grow(128)
         | 
| 13 | 
            -
                instance.runtime._start
         | 
| 14 | 
            -
              end
         | 
| 15 | 
            -
            else
         | 
| 16 | 
            -
              path = ARGV[0]
         | 
| 17 | 
            -
              method = ARGV[1]
         | 
| 18 | 
            -
              args = ARGV[2..-1] || []
         | 
| 19 | 
            -
              
         | 
| 20 | 
            -
              args = args.map do|a|
         | 
| 21 | 
            -
                if a.include? "."
         | 
| 22 | 
            -
                  a.to_f
         | 
| 23 | 
            -
                else
         | 
| 24 | 
            -
                  a.to_i
         | 
| 25 | 
            -
                end
         | 
| 26 | 
            -
              end
         | 
| 27 | 
            -
              ret = instance.runtime.call(method, args)
         | 
| 28 | 
            -
              $stderr.puts "return value: #{ret.inspect}"
         | 
| 29 | 
            -
            end
         | 
| 6 | 
            +
            cli = Wardite::Cli::Cli.new(ARGV)
         | 
| 7 | 
            +
            cli.run
         | 
| @@ -0,0 +1,135 @@ | |
| 1 | 
            +
            # rbs_inline: enabled
         | 
| 2 | 
            +
            require "optparse"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Wardite
         | 
| 5 | 
            +
              module Cli
         | 
| 6 | 
            +
                class Cli
         | 
| 7 | 
            +
                  # @rbs @args: Array[String]
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  attr_reader :invoke  #: String?
         | 
| 10 | 
            +
                  attr_reader :mapdir  #: String?
         | 
| 11 | 
            +
                  attr_reader :file    #: String
         | 
| 12 | 
            +
                  attr_reader :memsize #: Integer
         | 
| 13 | 
            +
                  attr_reader :wasi    #: bool
         | 
| 14 | 
            +
                  attr_reader :yjit    #: bool
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  # @rbs args: Array[String]
         | 
| 17 | 
            +
                  # @rbs return: void
         | 
| 18 | 
            +
                  def initialize(args)
         | 
| 19 | 
            +
                    @invoke = @mapdir = nil
         | 
| 20 | 
            +
                    @wasi = true # default to true
         | 
| 21 | 
            +
                    @yjit = false
         | 
| 22 | 
            +
                    @memsize = 1
         | 
| 23 | 
            +
                    options = OptionParser.new do |opts|
         | 
| 24 | 
            +
                      opts.version = Wardite::VERSION
         | 
| 25 | 
            +
                      opts.on("--invoke [fnname]", "Invoke the function") { |v|
         | 
| 26 | 
            +
                        @invoke = v
         | 
| 27 | 
            +
                      }
         | 
| 28 | 
            +
                      opts.on("--mapdir [dirs]", "Map the directory") { |v|
         | 
| 29 | 
            +
                        @mapdir = v
         | 
| 30 | 
            +
                      }
         | 
| 31 | 
            +
                      opts.on("--memsize [size_in_bytes]", "Initial memory size") { |v|
         | 
| 32 | 
            +
                        @memsize = (v.to_i / (64 * 1024).to_f).ceil.to_i
         | 
| 33 | 
            +
                      }
         | 
| 34 | 
            +
                      opts.on("--no-wasi", "Disable WASI feature") {|_v|
         | 
| 35 | 
            +
                        @wasi = false
         | 
| 36 | 
            +
                      }
         | 
| 37 | 
            +
                      opts.on("--yjit", "Enable yjit if available; setting WARDITE_YJIT_ON=1 has the same effect") {|_v|
         | 
| 38 | 
            +
                        @yjit = true
         | 
| 39 | 
            +
                      }
         | 
| 40 | 
            +
                      opts.on("FILE.wasm") { }
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                    options.parse!(args)
         | 
| 43 | 
            +
                    @file = args[0] || raise("require file argument")
         | 
| 44 | 
            +
                    @args = (args[1..-1] || [])
         | 
| 45 | 
            +
                    @args.unshift if @args[0] == '--'
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    if (yjit || ENV["WARDITE_YJIT_ON"] == "1") && (defined? RubyVM::YJIT)
         | 
| 48 | 
            +
                      RubyVM::YJIT.enable
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  # @rbs return: Array[Integer | Float]
         | 
| 53 | 
            +
                  # @rbs %a{pure}
         | 
| 54 | 
            +
                  def args
         | 
| 55 | 
            +
                    @args.map do |a|
         | 
| 56 | 
            +
                      if a.include? "."
         | 
| 57 | 
            +
                        a.to_f
         | 
| 58 | 
            +
                      else
         | 
| 59 | 
            +
                        a.to_i
         | 
| 60 | 
            +
                      end
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  # @rbs return: ::Wardite::Instance
         | 
| 65 | 
            +
                  def new_instance
         | 
| 66 | 
            +
                    f = File.open(file)
         | 
| 67 | 
            +
                    ins = Wardite::BinaryLoader::load_from_buffer(f, enable_wasi: wasi);
         | 
| 68 | 
            +
                    if memsize > 1
         | 
| 69 | 
            +
                      ins.store.memories[0].grow(memsize)
         | 
| 70 | 
            +
                    end
         | 
| 71 | 
            +
                    ins
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                  # @rbs return: void
         | 
| 75 | 
            +
                  def run
         | 
| 76 | 
            +
                    if invoke
         | 
| 77 | 
            +
                      invoke_function
         | 
| 78 | 
            +
                    else
         | 
| 79 | 
            +
                      if wasi
         | 
| 80 | 
            +
                        invoke_wasi
         | 
| 81 | 
            +
                        return
         | 
| 82 | 
            +
                      end
         | 
| 83 | 
            +
                      raise("requires function name to invoke")
         | 
| 84 | 
            +
                    end
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  # @rbs return: void
         | 
| 88 | 
            +
                  def invoke_function
         | 
| 89 | 
            +
                    unless invoke
         | 
| 90 | 
            +
                      raise "--invoke not set"
         | 
| 91 | 
            +
                    end
         | 
| 92 | 
            +
                    instance = new_instance
         | 
| 93 | 
            +
                    ret = instance.runtime.call(invoke, args)
         | 
| 94 | 
            +
                    $stderr.puts "return value: #{ret.inspect}"
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                  # @rbs return: void
         | 
| 98 | 
            +
                  def invoke_wasi
         | 
| 99 | 
            +
                    instance = new_instance #: ::Wardite::Instance
         | 
| 100 | 
            +
                    unless instance.wasi
         | 
| 101 | 
            +
                      raise "WASI not activated"
         | 
| 102 | 
            +
                    end
         | 
| 103 | 
            +
                    instance.wasi.argv = ["wardite"] + @args
         | 
| 104 | 
            +
                    if mapdir && mount_dst && mount_src
         | 
| 105 | 
            +
                      # TODO: support multiple mapdir
         | 
| 106 | 
            +
                      instance.wasi.mapdir[mount_dst] = mount_src
         | 
| 107 | 
            +
                      instance.wasi.set_preopened_dir(mount_dst, mount_src)
         | 
| 108 | 
            +
                    end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                    if defined? Bundler
         | 
| 111 | 
            +
                      Bundler.with_original_env do
         | 
| 112 | 
            +
                        instance.runtime._start
         | 
| 113 | 
            +
                      end
         | 
| 114 | 
            +
                    else
         | 
| 115 | 
            +
                      instance.runtime._start
         | 
| 116 | 
            +
                    end
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  # @rbs return: String?
         | 
| 120 | 
            +
                  # @rbs %a{pure}
         | 
| 121 | 
            +
                  def mount_src
         | 
| 122 | 
            +
                    mapdir&.split(":")&.first
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                  # @rbs return: String?
         | 
| 126 | 
            +
                  # @rbs %a{pure}
         | 
| 127 | 
            +
                  def mount_dst
         | 
| 128 | 
            +
                    m = mapdir&.split(":")
         | 
| 129 | 
            +
                    if m
         | 
| 130 | 
            +
                      m.size == 2 ? m[1] : m[0]
         | 
| 131 | 
            +
                    end
         | 
| 132 | 
            +
                  end
         | 
| 133 | 
            +
                end
         | 
| 134 | 
            +
              end
         | 
| 135 | 
            +
            end
         | 
    
        data/lib/wardite/value.rb
    CHANGED
    
    | @@ -383,7 +383,7 @@ module Wardite | |
| 383 383 | 
             
                  raise EvalError, "unsupported operation" if to != :f64
         | 
| 384 384 | 
             
                  v = [value].pack("L!").unpack("d")[0]
         | 
| 385 385 | 
             
                  raise EvalError, "[BUG] String#unpack is broke, really?" if !v.is_a?(Float)
         | 
| 386 | 
            -
                   | 
| 386 | 
            +
                  F64(v)
         | 
| 387 387 | 
             
                end
         | 
| 388 388 |  | 
| 389 389 | 
             
                # @rbs from: Symbol
         | 
    
        data/lib/wardite/version.rb
    CHANGED
    
    
    
        data/lib/wardite/wasi/consts.rb
    CHANGED
    
    | @@ -103,6 +103,13 @@ module Wardite | |
| 103 103 | 
             
                  RIGHT_PATH_REMOVE_DIRECTORY |
         | 
| 104 104 | 
             
                  RIGHT_PATH_UNLINK_FILE
         | 
| 105 105 |  | 
| 106 | 
            +
                LOOKUP_SYMLINK_FOLLOW = 1 << 0
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                O_CREAT = 1 << 0
         | 
| 109 | 
            +
                O_DIRECTORY = 1 << 1
         | 
| 110 | 
            +
                O_EXCL = 1 << 2
         | 
| 111 | 
            +
                O_TRUNC = 1 << 3
         | 
| 112 | 
            +
             | 
| 106 113 | 
             
                # @rbs mode_str: String
         | 
| 107 114 | 
             
                # @rbs return: Integer
         | 
| 108 115 | 
             
                def self.to_ftype(mode_str)
         | 
| @@ -0,0 +1,87 @@ | |
| 1 | 
            +
            # rbs_inline: enabled
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Wardite
         | 
| 4 | 
            +
              module Wasi
         | 
| 5 | 
            +
                class Dirent
         | 
| 6 | 
            +
                  attr_reader :path #: String
         | 
| 7 | 
            +
                  attr_reader :ino #: Integer
         | 
| 8 | 
            +
                  attr_reader :type #: Integer
         | 
| 9 | 
            +
                  
         | 
| 10 | 
            +
                  # @rbs path: String
         | 
| 11 | 
            +
                  # @rbs ino: Integer
         | 
| 12 | 
            +
                  # @rbs type: Integer
         | 
| 13 | 
            +
                  # @rbs return: void
         | 
| 14 | 
            +
                  def initialize(path, ino, type)
         | 
| 15 | 
            +
                    @path = path
         | 
| 16 | 
            +
                    @ino = ino
         | 
| 17 | 
            +
                    @type = type
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                class DirentCache
         | 
| 22 | 
            +
                  attr_reader :entries #: Array[Dirent]
         | 
| 23 | 
            +
                  attr_accessor :eof #: bool
         | 
| 24 | 
            +
                  
         | 
| 25 | 
            +
                  # @rbs path: String
         | 
| 26 | 
            +
                  # @rbs return: void
         | 
| 27 | 
            +
                  def initialize(path)
         | 
| 28 | 
            +
                    @entries = []
         | 
| 29 | 
            +
                    Dir.entries(path).sort.each do |entry|
         | 
| 30 | 
            +
                      case entry
         | 
| 31 | 
            +
                      when "."
         | 
| 32 | 
            +
                        @entries << Dirent.new(entry, File.stat(path).ino, FILETYPE_DIRECTORY)
         | 
| 33 | 
            +
                      when ".."
         | 
| 34 | 
            +
                        @entries << Dirent.new(entry, 0, FILETYPE_DIRECTORY)
         | 
| 35 | 
            +
                      else
         | 
| 36 | 
            +
                        full_path = File.join(path, entry)
         | 
| 37 | 
            +
                        type = case File.ftype(full_path)
         | 
| 38 | 
            +
                               when "directory" then FILETYPE_DIRECTORY
         | 
| 39 | 
            +
                               when "file"      then FILETYPE_REGULAR_FILE
         | 
| 40 | 
            +
                               when "link"      then FILETYPE_SYMBOLIC_LINK
         | 
| 41 | 
            +
                               else FILETYPE_UNKNOWN
         | 
| 42 | 
            +
                               end
         | 
| 43 | 
            +
                        @entries << Dirent.new(entry, File.stat(full_path).ino, type)
         | 
| 44 | 
            +
                      end
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    @eof = false
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  # @rbs buf_len: Integer
         | 
| 51 | 
            +
                  # @rbs cookie: Integer
         | 
| 52 | 
            +
                  # @rbs return: [String, bool]
         | 
| 53 | 
            +
                  def fetch_entries_binary(buf_len, cookie)
         | 
| 54 | 
            +
                    # d_next is the index of the next file in the list, so it should
         | 
| 55 | 
            +
                    # always be one higher than the requested cookie.
         | 
| 56 | 
            +
                    d_next = cookie + 1
         | 
| 57 | 
            +
                    buf = ""
         | 
| 58 | 
            +
                    entries_slice = entries[cookie..-1]
         | 
| 59 | 
            +
                    return "", false if entries_slice.nil? || entries_slice.empty?
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                    entries_slice.each do |entry|
         | 
| 62 | 
            +
                      data = make_dirent_pack1(d_next, entry.ino, entry.path.size, entry.type, entry.path)
         | 
| 63 | 
            +
                      if buf.size + data.size > buf_len
         | 
| 64 | 
            +
                        # truncated
         | 
| 65 | 
            +
                        return buf, true
         | 
| 66 | 
            +
                      end
         | 
| 67 | 
            +
                      buf += data
         | 
| 68 | 
            +
                      d_next += 1
         | 
| 69 | 
            +
                    end
         | 
| 70 | 
            +
                    
         | 
| 71 | 
            +
                    return buf, false
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                  # @rbs d_next: Integer
         | 
| 75 | 
            +
                  # @rbs ino: Integer
         | 
| 76 | 
            +
                  # @rbs name_len: Integer
         | 
| 77 | 
            +
                  # @rbs type: Integer
         | 
| 78 | 
            +
                  # @rbs name: String
         | 
| 79 | 
            +
                  # @rbs return: String
         | 
| 80 | 
            +
                  def make_dirent_pack1(d_next, ino, name_len, type, name)
         | 
| 81 | 
            +
                    data = [d_next, ino, name_len, type].pack("Q! Q! I! I!")
         | 
| 82 | 
            +
                    data += name
         | 
| 83 | 
            +
                    data
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            # rbs_inline: enabled
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Wardite
         | 
| 4 | 
            +
              module Wasi
         | 
| 5 | 
            +
                class PreopenedDir
         | 
| 6 | 
            +
                  attr_reader :path #: String
         | 
| 7 | 
            +
                  attr_reader :guest_path #: String
         | 
| 8 | 
            +
                  attr_reader :fd #: Integer
         | 
| 9 | 
            +
                  
         | 
| 10 | 
            +
                  def initialize(path, guest_path, fd)
         | 
| 11 | 
            +
                    @path = path
         | 
| 12 | 
            +
                    @guest_path = guest_path
         | 
| 13 | 
            +
                    @fd = fd
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         |