lib/buildbox/command.rb in buildbox-0.2.2 vs lib/buildbox/command.rb in buildbox-0.2.3
- old
+ new
@@ -1,67 +1,74 @@
+require 'childprocess'
require 'pty'
module Buildbox
class Command
class Result < Struct.new(:output, :exit_status)
end
- def self.run(command, options = {}, &block)
- new(command, options).run(&block)
+ def self.command(command, options = {}, &block)
+ new(command, options).start(&block)
end
- def initialize(command, options = {})
- @command = command
+ def self.script(script, options = {}, &block)
+ new(script, options).start(&block)
+ end
+
+ def initialize(arguments, options = {})
+ @arguments = arguments
+ @environment = options[:environment] || {}
@directory = options[:directory] || "."
- @read_interval = options[:read_interval] || 5
end
- def run(&block)
- output = ""
- read_io, write_io, pid = nil
+ def start(&block)
+ read_io, write_io = IO.pipe
- # spawn the process in a pseudo terminal so colors out outputted
- read_io, write_io, pid = PTY.spawn("cd #{expanded_directory} && #{@command}")
+ arguments = [ *runner, *@arguments ].compact.map(&:to_s) # all arguments must be a string
+ process = ChildProcess.build(*arguments)
+ process.cwd = expanded_directory
+ process.io.stdout = process.io.stderr = write_io
- # we don't need to write to the spawned io
+ @environment.each_pair do |key, value|
+ process.environment[key] = value
+ end
+
+ process.start
write_io.close
- loop do
- fds, = IO.select([read_io], nil, nil, read_interval)
- if fds
- # should have some data to read
- begin
- chunk = read_io.read_nonblock(10240)
- cleaned_chunk = UTF8.clean(chunk)
+ output = ""
+ begin
+ loop do
+ chunk = read_io.readpartial(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
+ output << chunk
+ yield cleaned_chunk if block_given?
end
- # if fds are empty, timeout expired - run another iteration
+ rescue EOFError
end
- # we're done reading, yay!
- read_io.close
+ process.wait
- # just wait until its finally finished closing
- Process.waitpid(pid)
-
# the final result!
- Result.new(output.chomp, $?.exitstatus)
+ Result.new(output.chomp, process.exit_code)
end
private
- def expanded_directory
- File.expand_path(@directory)
+ # on heroku, tty isn't avaiable. so we result to just running command through
+ # bash. the downside to this, is that stuff colors aren't outputted because
+ # processes don't think they're being in a terminal.
+ def runner
+ require 'pty'
+ PTY.spawn('whoami')
+
+ [ File.join(Buildbox.gem_root, "bin", "buildbox-pty") ]
+ rescue
+ [ "bash", "-c" ]
end
- def read_interval
- @read_interval
+ def expanded_directory
+ File.expand_path(@directory)
end
end
end