Commit 11d150bb authored by Fabio Pelosin's avatar Fabio Pelosin

[Executable] Cleaned up implementation.

parent 709137d9
require 'open4' require 'open4'
module Pod module Pod
# Module which provides support for running executables.
#
# In a class it can be used as:
#
# extend Executable
# executable :git
#
# This will create two methods `git` and `git!` both accept a command but
# the later will raise on non successful executions. The methods return the
# output of the command.
#
module Executable module Executable
class Indenter < ::Array
include Config::Mixin
attr_accessor :indent # Creates the methods for the executable with the given name.
attr_accessor :io #
# @param [Symbol] name
# the name of the executable.
#
# @raise If the executable could not be located.
#
# @return [void]
#
def executable(name)
bin = `which #{name}`.strip
raise Informative, "Unable to locate the executable `#{name}`" if bin.empty?
def initialize(io = nil) define_method(name) do |command|
@io = io Executable.execute_command(bin, command, false)
@indent = ' ' * UI.indentation_level
end end
def <<(value) define_method(name.to_s + "!") do |command|
super Executable.execute_command(bin, command, true)
ensure
@io << "#{ indent }#{ value }" if @io
end end
end end
# Executes the given command displaying it if in verbose mode.
# TODO #
# @param [String] bin
# The binary to use.
#
# @param [String] command
# The command to send to the binary.
#
# @param [Bool] raise_on_failure
# Whether it should raise if the command fails.
#
# @raise If the command fails and the `raise_on_failure` is set to true.
#
# @return [String] the output of the command (STDOUT and STDERR).
#
# @todo Find a way to display the live output of the commands.
# #
def self.execute_command(bin, command, raise_on_failure = false) def self.execute_command(bin, command, raise_on_failure = false)
bin = `which #{bin}`.strip
if bin.empty?
raise Informative, "Unable to locate the executable `#{name}'"
end
full_command = "#{bin} #{command}" full_command = "#{bin} #{command}"
if Config.instance.verbose? if Config.instance.verbose?
UI.message("$ #{full_command}") UI.message("$ #{full_command}")
stdout, stderr = Indenter.new(STDOUT), Indenter.new(STDERR) stdout, stderr = Indenter.new(STDOUT), Indenter.new(STDERR)
else else
stdout, stderr = Indenter.new, Indenter.new stdout, stderr = Indenter.new, Indenter.new
end end
status = Open4.spawn(full_command, :stdout => stdout, :stderr => stderr, :status => true)
output = stdout.join("\n") + stderr.join("\n") # TODO will this suffice? options = {:stdout => stdout, :stderr => stderr, :status => true}
status = Open4.spawn(full_command, options)
output = stdout.join("\n") + stderr.join("\n")
unless status.success? unless status.success?
if raise_on_failure if raise_on_failure
raise Informative, "#{name} #{command}\n\n#{output}" raise Informative, "#{name} #{command}\n\n#{output}"
...@@ -48,43 +77,41 @@ module Pod ...@@ -48,43 +77,41 @@ module Pod
output output
end end
#-------------------------------------------------------------------------#
def executable(name) # Helper class that allows to write to an {IO} instance taking into account
bin = `which #{name}`.strip # the UI indentation lever.
base_method = "base_" << name.to_s #
define_method(base_method) do |command, should_raise| class Indenter < ::Array
if bin.empty? include Config::Mixin
raise Informative, "Unable to locate the executable `#{name}'"
end
full_command = "#{bin} #{command}"
if Config.instance.verbose?
UI.message("$ #{full_command}")
stdout, stderr = Indenter.new(STDOUT), Indenter.new(STDERR)
else
stdout, stderr = Indenter.new, Indenter.new
end
status = Open4.spawn(full_command, :stdout => stdout, :stderr => stderr, :status => true)
output = stdout.join("\n") + stderr.join("\n") # TODO will this suffice? # @return [Fixnum] The indentation level of the UI.
unless status.success? #
if should_raise attr_accessor :indent
raise Informative, "#{name} #{command}\n\n#{output}"
else
UI.message("[!] Failed: #{full_command}".red)
end
end
output
end
define_method(name) do |command| # @return [IO] the {IO} to which the output should be printed.
Executable.execute_command(name, command, false) #
end attr_accessor :io
define_method(name.to_s + "!") do |command| # @param [IO] io @see io
Executable.execute_command(name, command, true) #
def initialize(io = nil)
@io = io
@indent = ' ' * UI.indentation_level
end end
private name # Stores a portion of the output and prints it to the {IO} instance.
#
# @param [String] value
# the output to print.
#
# @return [void]
#
def <<(value)
super
ensure
@io << "#{ indent }#{ value }" if @io
end
end end
end end
end end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment