Module: BrowserifyRb::Popen3

Defined in:
lib/browserify_rb/popen3.rb

Constant Summary collapse

LOG =
Logger.new(STDERR)
CHUNK_SIZE =
2000
DEFAULT_STDOUT_HANDLER =
proc {|data| STDOUT.print data }
DEFAULT_STDERR_HANDLER =
proc {|data| STDERR.print data }

Class Method Summary collapse

Class Method Details

.async_exec(input: "", env: {}, cmd: nil, stdout_handler: DEFAULT_STDOUT_HANDLER, stderr_handler: DEFAULT_STDERR_HANDLER, spawn_opts: {}, chunk_size: CHUNK_SIZE) ⇒ Object

Raises:

  • (ArgumentError)


13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/browserify_rb/popen3.rb', line 13

def self.async_exec(
      input: "",
      env: {},
      cmd: nil,
      stdout_handler: DEFAULT_STDOUT_HANDLER,
      stderr_handler: DEFAULT_STDERR_HANDLER,
      spawn_opts: {},
      chunk_size: CHUNK_SIZE)

  raise ArgumentError, "'cmd' require" if cmd.nil?

  stdin, stdout, stderr, wait_thr = Open3.popen3 env, cmd, spawn_opts

  in_buf = StringIO.new input
  opened_ins = [stdin]
  opened_outs = [stdout, stderr]

  Thread.fork do
    begin
      while not opened_outs.empty?
        ios = IO.select opened_outs, opened_ins, nil, 1
        if ios.nil? and Process.waitpid(wait_thr.pid, Process::WNOHANG)
          break
        end

        outs, ins, = ios

        unless outs.nil?
          if outs.include? stdout
            begin
              d = stdout.readpartial CHUNK_SIZE
              stdout_handler.yield d
            rescue EOFError
              opened_outs.delete stdout
            end
          end

          if outs.include? stderr
            begin
              d = stderr.readpartial CHUNK_SIZE
              stderr_handler.yield d
            rescue EOFError
              opened_outs.delete stderr
            end
          end
        end

        if not ins.nil? and ins.include? stdin
          i = begin
                in_buf.readpartial CHUNK_SIZE
              rescue EOFError
                nil
              end
          if i.nil?
            stdin.close
            opened_ins.delete stdin
          else
            bytes = stdin.write_nonblock(i)
            in_buf.seek bytes - i.bytesize, IO::SEEK_CUR
          end
        end
      end
    rescue => e
      LOG.error e
    end
  end

  wait_thr
end