lib/rake/funnel/extensions/shell.rb in rake-funnel-0.3.2.pre vs lib/rake/funnel/extensions/shell.rb in rake-funnel-0.4.0.pre

- old
+ new

@@ -1,56 +1,92 @@ -require 'rake' -require 'open3' -require 'smart_colored/extend' - -module Rake::Funnel::Extensions - module Shell - def shell(*cmd, log_file: nil, error_lines: nil) - mkdir_p(File.dirname(log_file)) if log_file - - stdout = -> (msg) { $stdout.puts msg.sub(/\n$/, '').green } - - error_logged = false - stderr = -> (msg) { - error_logged = true - $stderr.puts msg.sub(/\n$/, '').bold.red - } - - log = StringIO.new - - begin - cmd = cmd.flatten.reject(&:nil?) - Rake.rake_output_message(cmd.join(' ')) - - Open3.popen2e(*cmd) do |_, stdout_and_stderr, wait_thread| - stdout_and_stderr.each do |line| - out = stdout - out = stderr if error_lines && line =~ error_lines - out.call(line) - - log.write(line) - File.open(log_file, 'a') { |f| f.write(line) } if log_file - end - - success = wait_thread.value.success? && error_logged == false - result = [cmd.join(' '), - wait_thread.value.exitstatus, - log.string] - - if block_given? - yield(success, *result) - return - end - - raise Rake::Funnel::ExecutionError.new(*result) unless success - end - ensure - log.close - end - end - end -end - -module Rake::DSL - include Rake::Funnel::Extensions::Shell - private(*Rake::Funnel::Extensions::Shell.instance_methods(false)) -end +require 'rake' +require 'open3' +require 'smart_colored/extend' +require 'stringio' + +module Rake + module Funnel + module Extensions + module Shell + def shell(*cmd, log_file: nil, error_lines: nil, &block) + mkdir_p(File.dirname(log_file)) if log_file + + run(cmd, log_file, error_lines) do |success, readable_cmd, result, log| + if block + block.call(success, readable_cmd, result, log) + return + end + end + end + + private + def run(cmd, log_file, error_lines) + cmd, readable_cmd = normalize(cmd) + + Rake.rake_output_message(readable_cmd) + + Open3.popen2e(*cmd) do |_, stdout_and_stderr, wait_thread| + log, error_logged = log_output(stdout_and_stderr, log_file, error_lines) + success = wait_thread.value.success? && error_logged == false + + result = [readable_cmd, wait_thread.value.exitstatus, log] + + yield(success, *result) if block_given? + + fail Rake::Funnel::ExecutionError.new(*result) unless success + end + end + + def normalize(cmd) + cmd = cmd.flatten.reject(&:nil?) + readable_cmd = cmd.join(' ') + + [cmd, readable_cmd] + end + + def log_output(stdout_and_stderr, log_file, error_lines) + log_string = StringIO.new + + begin + statuses = log_lines(stdout_and_stderr, log_file, error_lines, log_string) + + [log_string.string, statuses.any? { |s| s == :error }] + ensure + log_string.close + end + end + + def log_lines(stdout_and_stderr, log_file, error_lines, log_string) + stdout_and_stderr.map do |line| + log_string.write(line) + File.open(log_file, 'a') { |f| f.write(line) } if log_file + + handle_line(line, error_lines) + end + end + + def handle_line(line, error_lines) + to_stderr(line, error_lines) || to_stdout(line) + end + + def to_stdout(line) + $stdout.puts line.sub(/\n$/, '').green + :success + end + + def to_stderr(line, error_lines) + return unless error_lines && line =~ error_lines + + $stderr.puts line.sub(/\n$/, '').bold.red + :error + end + end + end + end +end + +module Rake + module DSL + include Rake::Funnel::Extensions::Shell + private(*Rake::Funnel::Extensions::Shell.instance_methods(false)) + end +end