lib/buildbox/command.rb in buildbox-0.0.4 vs lib/buildbox/command.rb in buildbox-0.1
- old
+ new
@@ -1,73 +1,67 @@
+require 'pty'
+
module Buildbox
class Command
- require 'pty'
+ class Result < Struct.new(:output, :exit_status)
+ end
- class Error < StandardError; end
+ def self.run(command, options = {}, &block)
+ new(command, options).run(&block)
+ end
- def initialize(path = nil, read_interval = nil)
- @path = path || "."
- @read_interval = read_interval || 5
+ def initialize(command, options = {})
+ @command = command
+ @directory = options[:directory] || "."
+ @read_interval = options[:read_interval] || 5
end
- def run(command)
- Buildbox.logger.debug(command)
-
+ def run(&block)
+ output = ""
read_io, write_io, pid = nil
- result = Buildbox::Result.new(command)
- # hack: this is so the observer class can raise a started event.
- # instead of having a block passed to this command, we should implement
- # a proper command observer
- yield result
+ # spawn the process in a pseudo terminal so colors out outputted
+ read_io, write_io, pid = PTY.spawn("cd #{expanded_directory} && #{@command}")
- begin
- dir = File.expand_path(@path)
-
- # spawn the process in a pseudo terminal so colors out outputted
- read_io, write_io, pid = PTY.spawn("cd #{dir} && #{command}")
- rescue Errno::ENOENT => e
- return Buildbox::Result.new(false, e.message)
- end
-
+ # we don't need to write to the spawned io
write_io.close
loop do
- fds, = IO.select([read_io], nil, nil, @read_interval)
+ fds, = IO.select([read_io], nil, nil, read_interval)
if fds
# should have some data to read
begin
- chunk = read_io.read_nonblock(10240)
- if block_given?
- yield result, chunk
- end
- result.output += chunk
+ chunk = read_io.read_nonblock(10240)
+ cleaned_chunk = UTF8.clean(chunk)
+
+ output << chunk
+ yield cleaned_chunk if block_given?
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
# do select again
rescue EOFError, Errno::EIO # EOFError from OSX, EIO is raised by ubuntu
break
end
end
# if fds are empty, timeout expired - run another iteration
end
+ # we're done reading, yay!
read_io.close
+
+ # just wait until its finally finished closing
Process.waitpid(pid)
- # output may be invalid UTF-8, as it is produced by the build command.
- result.finished = true
- result.exit_status = $?.exitstatus
-
- result
+ # the final result!
+ Result.new(output.chomp, $?.exitstatus)
end
- def run!(command)
- result = run(command)
+ private
- unless result.success?
- raise Error, "Failed to run '#{command}': #{result.output}"
- end
+ def expanded_directory
+ File.expand_path(@directory)
+ end
- result
+ def read_interval
+ @read_interval
end
end
end