Class: Pups::ExecCommand

Inherits:
Command show all
Defined in:
lib/pups/exec_command.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Command

#interpolate_params, interpolate_params, run

Constructor Details

#initialize(params, cd = nil) ⇒ ExecCommand

Returns a new instance of ExecCommand.



61
62
63
64
65
66
# File 'lib/pups/exec_command.rb', line 61

def initialize(params, cd = nil)
  @commands = []
  @params = params
  @cd = interpolate_params(cd)
  @raise_on_fail = true
end

Instance Attribute Details

#backgroundObject

Returns the value of attribute background.



5
6
7
# File 'lib/pups/exec_command.rb', line 5

def background
  @background
end

#cdObject (readonly)

Returns the value of attribute cd.



4
5
6
# File 'lib/pups/exec_command.rb', line 4

def cd
  @cd
end

#commandsObject (readonly)

Returns the value of attribute commands.



4
5
6
# File 'lib/pups/exec_command.rb', line 4

def commands
  @commands
end

#raise_on_failObject

Returns the value of attribute raise_on_fail.



5
6
7
# File 'lib/pups/exec_command.rb', line 5

def raise_on_fail
  @raise_on_fail
end

#stdinObject

Returns the value of attribute stdin.



5
6
7
# File 'lib/pups/exec_command.rb', line 5

def stdin
  @stdin
end

#stop_signalObject

Returns the value of attribute stop_signal.



5
6
7
# File 'lib/pups/exec_command.rb', line 5

def stop_signal
  @stop_signal
end

Class Method Details

.from_hash(hash, params) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/pups/exec_command.rb', line 39

def self.from_hash(hash, params)
  cmd = new(params, hash["cd"])

  case c = hash["cmd"]
  when String then cmd.add(c)
  when Array then c.each{|i| cmd.add(i)}
  end

  cmd.background = hash["background"]
  cmd.stop_signal = hash["stop_signal"] || "TERM"
  cmd.raise_on_fail = hash["raise_on_fail"] if hash.key? "raise_on_fail"
  cmd.stdin = interpolate_params(hash["stdin"], params)

  cmd
end

.from_str(str, params) ⇒ Object



55
56
57
58
59
# File 'lib/pups/exec_command.rb', line 55

def self.from_str(str, params)
  cmd = new(params)
  cmd.add(str)
  cmd
end

.terminate_async(opts = {}) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/pups/exec_command.rb', line 7

def self.terminate_async(opts={})

  return unless defined? @@asyncs

  Pups.log.info("Terminating async processes")

  @@asyncs.each do |async|
    Pups.log.info("Sending #{async[:stop_signal]} to #{async[:command]} pid: #{async[:pid]}")
    Process.kill(async[:stop_signal],async[:pid]) rescue nil
  end

  @@asyncs.map do |async|
    Thread.new do
      begin
        Timeout.timeout(opts[:wait] || 10) do
          Process.wait(async[:pid]) rescue nil
        end
      rescue Timeout::Error
        Pups.log.info("#{async[:command]} pid:#{async[:pid]} did not terminate cleanly, forcing termination!")
        begin
          Process.kill("KILL",async[:pid])
          Process.wait(async[:pid])
        rescue Errno::ESRCH
        rescue Errno::ECHILD
        end

      end
    end
  end.each(&:join)

end

Instance Method Details

#add(cmd) ⇒ Object



68
69
70
# File 'lib/pups/exec_command.rb', line 68

def add(cmd)
  @commands << process_params(cmd)
end

#process_params(cmd) ⇒ Object



111
112
113
114
# File 'lib/pups/exec_command.rb', line 111

def process_params(cmd)
  processed = interpolate_params(cmd)
  @cd ? "cd #{cd} && #{processed}" : processed
end

#runObject



72
73
74
75
76
77
78
79
80
81
# File 'lib/pups/exec_command.rb', line 72

def run
  commands.each do |command|
    Pups.log.info("> #{command}")
    pid = spawn(command)
    Pups.log.info(@result.readlines.join("\n")) if @result
    pid
  end
rescue
  raise if @raise_on_fail
end

#spawn(command) ⇒ Object

Raises:

  • (RuntimeError)


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/pups/exec_command.rb', line 83

def spawn(command)
  if background
    pid = Process.spawn(command)
    (@@asyncs ||= []) << {pid: pid, command: command, stop_signal: (stop_signal || "TERM")}
    Thread.new do
      Process.wait(pid)
      @@asyncs.delete_if{|async| async[:pid] == pid}
    end
    return pid
  end

  IO.popen(command, "w+") do |f|
    if stdin
      # need a way to get stdout without blocking
      Pups.log.info(stdin)
      f.write stdin
      f.close
    else
      Pups.log.info(f.readlines.join)
    end
  end

  raise RuntimeError.new("#{command} failed with return #{$?.inspect}") unless $? == 0

  nil

end