Commit 77bc3c6

mo khan <mo.khan@gmail.com>
2019-10-19 20:57:01
hack together test script
1 parent 4d15bf2
Changed files (3)
bin/test
@@ -0,0 +1,7 @@
+#!/usr/bin/env ruby
+
+$LOAD_PATH.unshift(File.expand_path(File.join(__dir__, '../lib')))
+
+require 'jive'
+
+exit Jive.run([%w[bundle exec rspec]])
exe/jive
lib/jive.rb
@@ -1,6 +1,144 @@
+# frozen_string_literal: true
+
+require "fileutils"
 require "jive/version"
+require "open3"
 
 module Jive
   class Error < StandardError; end
-  # Your code goes here...
+
+  def self.run(tasks)
+    Jive::BatchRunner.new.run(tasks)
+  end
+
+  module Popen
+    Result = Struct.new(:command, :stdout, :stderr, :status, :duration)
+
+    def self.popen(command, path = nil, env = {}, &block)
+      result = popen_with_detail(command, path, env, &block)
+
+      ["#{result.stdout}#{result.stderr}", result.status&.exitstatus]
+    end
+
+    def self.popen_with_detail(command, path = Dir.pwd, env = {})
+      FileUtils.mkdir_p(path) unless File.directory?(path)
+
+      captured_stdout = ''
+      captured_stderr = ''
+      exit_status = nil
+      start = Time.now
+
+      Open3.popen3(env.merge('PWD' => path), *Array(command), { chdir: path }) do |stdin, stdout, stderr, wait_thr|
+        out_reader = Thread.new { stdout.read }
+        err_reader = Thread.new { stderr.read }
+
+        yield(stdin) if block_given?
+
+        stdin.close
+        captured_stdout = out_reader.value
+        captured_stderr = err_reader.value
+        exit_status = wait_thr.value
+      end
+      Result.new(command, captured_stdout, captured_stderr, exit_status, Time.now - start)
+    end
+  end
+
+  class BatchRunner
+    attr_reader :runner, :stdout
+
+    def initialize(runner: Runner.new, stdout: STDOUT)
+      @runner = runner
+      @stdout = stdout
+    end
+
+    def run(tasks, verbose: true)
+      runner.run(tasks) do |command, &run|
+        stdout.puts
+        stdout.puts "$ #{command.join(' ')}"
+        result = run.call
+        stdout.print result.stdout if verbose
+        stdout.print result.stderr if verbose
+        stdout.puts "==> Finished in #{result.duration} seconds"
+        stdout.puts
+      end
+      stdout.puts '==================================================='
+      if runner.all_success_and_clean?
+        stdout.puts 'Passed successfully.'
+        return 0
+      elsif runner.all_success?
+        stdout.puts 'Passed successfully, but we have warnings:'
+        stdout.puts
+        emit_warnings
+        return 2
+      else
+        stdout.puts 'Something failed:'
+        emit_warnings
+        emit_errors
+        return 1
+      end
+    end
+
+    private
+
+    def emit_warnings
+      runner.warned_results.each do |result|
+        stdout.puts
+        stdout.puts "**** #{result.command.join(' ')} had the following warning(s):"
+        stdout.puts
+        stdout.puts result.stderr
+        stdout.puts
+      end
+    end
+
+    def emit_errors
+      runner.failed_results.each do |result|
+        stdout.puts
+        stdout.puts "**** #{result.command.join(' ')} failed with the following error(s):"
+        stdout.puts
+        stdout.puts result.stdout
+        stdout.puts result.stderr
+        stdout.puts
+      end
+    end
+  end
+
+  class Runner
+    attr_reader :results
+
+    def initialize
+      @results = []
+    end
+
+    def run(commands, &block)
+      commands.each do |command|
+        block.call(command) do
+          cmd_result = Popen.popen_with_detail(command)
+          results << cmd_result
+          cmd_result
+        end
+      end
+    end
+
+    def all_success_and_clean?
+      all_success? && all_stderr_empty?
+    end
+
+    def all_success?
+      results.all? { |result| result.status.success? }
+    end
+
+    def all_stderr_empty?
+      results.all? { |result| result.stderr.empty? }
+    end
+
+    def failed_results
+      results.reject { |result| result.status.success? }
+    end
+
+    def warned_results
+      results.select do |result|
+        result.status.success? && !result.stderr.empty?
+      end
+    end
+  end
 end