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