module Albacore::CrossPlatformCmd
module for normalising slashes across operating systems and running commands
Constants
- KILL_TIMEOUT
Attributes
pid[R]
Public Class Methods
new()
click to toggle source
# File lib/albacore/cross_platform_cmd.rb, line 45 def initialize pid = Process.pid at_exit { stop if Process.pid == pid } end
Public Instance Methods
chdir(wd, &block)
click to toggle source
# File lib/albacore/cross_platform_cmd.rb, line 219 def chdir wd, &block return block.call if wd.nil? Dir.chdir wd do debug { "pushd #{wd} [cross_platform_cmd #chdir]" } res = block.call debug { "popd #{wd} [cross_platform_cmd #chdir]" } return res end end
make_command()
click to toggle source
create a new command string
# File lib/albacore/cross_platform_cmd.rb, line 182 def make_command ::Albacore::Paths.make_command @executable, @parameters end
normalise_slashes(path)
click to toggle source
# File lib/albacore/cross_platform_cmd.rb, line 177 def normalise_slashes path ::Albacore::Paths.normalise_slashes path end
sh(*cmd, &block)
click to toggle source
run in shell
# File lib/albacore/cross_platform_cmd.rb, line 140 def sh *cmd, &block raise ArgumentError, "cmd is nil" if cmd.nil? # don't allow nothing to be passed opts = Map.options((Hash === cmd.last) ? cmd.pop : {}) # same arg parsing as rake cmd = cmd.join(' ') # shell needs a single string block = handler_with_message cmd unless block_given? chdir opts.get(:work_dir) do trace { "#sh( ..., options: #{opts.to_s}) [cross_platform_cmd #sh]" } puts cmd unless opts.getopt :silent, false # log cmd verbatim lines = '' handle_not_found block do IO.popen(cmd, 'r') do |io| io.each do |line| lines << line puts line if opts.getopt(:output, true) or not opts.getopt(:silent, false) end end end return block.call($? == 0 && lines, $?, lines) end end
shie(*cmd, &block)
click to toggle source
shell ignore exit code returns:
[ok, status] where status: #exitstatus : Int #pid : Int
# File lib/albacore/cross_platform_cmd.rb, line 172 def shie *cmd, &block block = lambda { |ok, status, output| ok } unless block_given? sh *cmd, &block end
stop()
click to toggle source
# File lib/albacore/cross_platform_cmd.rb, line 115 def stop if pid begin Process.kill('TERM', pid) begin Timeout.timeout(KILL_TIMEOUT) { Process.wait(pid) } rescue Timeout::Error Process.kill('KILL', pid) Process.wait(pid) end rescue Errno::ESRCH, Errno::ECHILD # Zed's dead, baby end @out_thread.kill @pid = nil end end
system(*cmd, &block)
click to toggle source
run executable
system(cmd, [args array], Hash(opts), block|ok,status|)
ok => false if bad exit code, or the output otherwise
options are passed as the last argument
options:
work_dir: a file path (default '.') silent: whether to supress all output or not (default false) output: whether to supress the command's output (default false) out: output pipe err: error pipe clr_command: whether to include 'mono' in front of the things to run if the command is a clr command
# File lib/albacore/cross_platform_cmd.rb, line 67 def system *cmd, &block raise ArgumentError, "cmd is nil" if cmd.nil? # don't allow nothing to be passed opts = Map.options((Hash === cmd.last) ? cmd.pop : {}). # same arg parsing as rake apply({ :silent => false, :output => true, :work_dir => FileUtils.pwd, :out => Albacore.application.output, :err => Albacore.application.output_err, :clr_command => false }) exe, pars, printable, block = prepare_command cmd, (opts.get('clr_command')), &block # TODO: figure out how to interleave output and error streams out, _, inmem = opts.get(:out), opts.get(:err), StringIO.new trace { "system( exe=#{exe}, pars=[#{pars.join(', ')}], options=#{opts.to_s}), in directory: #{opts.getopt(:work_dir, '<<current>>')} [cross_platform_cmd #system]" } puts printable unless opts.get :silent, false # log cmd verbatim handle_not_found block do # create a pipe for the process to work with read, write = IO.pipe eread, ewrite = IO.pipe # this thread chews through the output @out_thread = Thread.new { while !read.eof? data = read.readpartial(1024) out.write data inmem.write data # to give the block at the end end } debug 'execute the new process, letting it write to the write FD (file descriptor)' @pid = Process.spawn(*[exe, *pars], { :out => write, #:err => ewrite, :chdir => opts.get(:work_dir) }) debug 'waiting for process completion' _, status = Process.wait2 @pid ret_str = inmem.string.encode 'utf-8', invalid: :replace, undef: :replace, replace: '' return block.call(status.success? && ret_str, status, ret_str) end end
which(executable)
click to toggle source
# File lib/albacore/cross_platform_cmd.rb, line 186 def which executable raise ArgumentError, "executable to #which is nil" unless executable dir = File.dirname executable file = File.basename executable cmd = ::Rake::Win32.windows? ? 'where' : 'which' parameters = [] pattern = if dir == '.' then file elsif ::Rake::Win32.windows? then "#{dir}:#{file}" else executable end parameters << Paths.normalise_slashes("\"#{pattern}\"") parameters << '2> nul' if ::Rake::Win32.windows? cmd, parameters = Paths.normalise cmd, parameters cmd = "#{cmd} #{parameters.join(' ')}" trace { "#{cmd} [cross_platform_cmd #which]" } res = IO.popen(cmd) do |io| io.read.chomp end unless $? == 0 nil else res end rescue Errno::ENOENT => e trace "which/where returned #{$?}: #{e} [cross_platform_cmd #which]" nil end
Private Instance Methods
format_failure(cmd, status)
click to toggle source
# File lib/albacore/cross_platform_cmd.rb, line 267 def format_failure cmd, status if knowns.has_key? status.exitstatus %{Command failed with status (#{status.exitstatus}) - #{knowns[status.exitstatus]}: #{cmd}} else %{Command failed with status (#{status.exitstatus}): #{cmd}} end end
handle_not_found(rescue_block) { || ... }
click to toggle source
handles the errors from not finding the executable on the system
# File lib/albacore/cross_platform_cmd.rb, line 246 def handle_not_found rescue_block yield rescue Errno::ENOENT => e rescue_block.call(nil, PseudoStatus.new(127), e.to_s) rescue IOError => e # rescue for JRuby rescue_block.call(nil, PseudoStatus.new(127), e.to_s) end
handler_with_message(printable)
click to toggle source
# File lib/albacore/cross_platform_cmd.rb, line 241 def handler_with_message printable lambda { |ok, status, output| ok or raise_failure(printable, status, output) } end
knowns()
click to toggle source
# File lib/albacore/cross_platform_cmd.rb, line 255 def knowns { 127 => 'number 127 in particular means that the operating system could not find the executable' } end
mono_command()
click to toggle source
shuffle the executable to be a parameter to mono, if not on windows.
# File lib/albacore/cross_platform_cmd.rb, line 279 def mono_command unless ::Rake::Win32.windows? trace 'detected running on mono -- unshifting exe file for mono' executable = @executable @executable = "mono" @parameters.unshift executable end end
prepare_command(cmd, clr_command = false, &block)
click to toggle source
# File lib/albacore/cross_platform_cmd.rb, line 231 def prepare_command cmd, clr_command = false, &block cmd = cmd.unshift 'mono' if clr_command && ! ::Albacore.windows? pars = cmd[1..-1].flatten raise ArgumentError, "arguments 1..-1 must be an array" unless pars.is_a? Array exe, pars = ::Albacore::Paths.normalise cmd[0], pars printable = %Q{#{exe} #{pars.join(' ')}} handler = block_given? ? block : handler_with_message(printable) [exe, pars, printable, handler] end
raise_failure(cmd, status, output)
click to toggle source
# File lib/albacore/cross_platform_cmd.rb, line 259 def raise_failure cmd, status, output if status.exitstatus == 127 raise CommandNotFoundError.new(format_failure(cmd, status), cmd) else raise CommandFailedError.new(format_failure(cmd, status), cmd, output) end end