qbash 0.4.4 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/lib/qbash.rb +27 -21
  3. data/qbash.gemspec +1 -1
  4. data/test/test_qbash.rb +48 -1
  5. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 352743a00eafd7847765e2839c66af94008228e5d614ef58c6e615f855376d20
4
- data.tar.gz: b61577f89976eabc074146be11a9b8800aeaefdda100c98d4d5abd51a6dba688
3
+ metadata.gz: 1ca64f77c050b51b02164ffab0c532d6d915fe0ba76ed4d311894b150eac963f
4
+ data.tar.gz: 4082a2f3aadf655a8fe6a6b7df67a85212f0fe9b8221bf64a26329abdfb8218a
5
5
  SHA512:
6
- metadata.gz: ef6de7a925ffe5b06c44bdca42efb852016dcab80bb52d8c41646e6ef6a306f2e73500e62840dd6d04c24d6545fdf4016e0f55161c0225abbac95ba50c4e2dae
7
- data.tar.gz: 46d7a56a167241d0deed6dc5596efa2dfbe3dfa96fa1694e9c8cad5003be994f4f686c744122b71f8da4c42aa324ce77b57c6d5c3d4cd7b40061a6f2a5eae08e
6
+ metadata.gz: 80535d4feebc803f62b1da69da63f2412330cc8f21a8ca9a5cfc344535b2c15c6816df65fcaa16db40efff702b8628dcd7817a4b93003a423b8928ea3df82d25
7
+ data.tar.gz: 609155111977c724663a6ba5c6a90718252d0c520f608c3dcadf0abc80dc0bf5d135f27a1204cfc9a002371461c9ff2e8cff85b9862dc6404fc2baf0a9a70932
data/lib/qbash.rb CHANGED
@@ -75,17 +75,19 @@ module Kernel
75
75
  #
76
76
  # @param [String, Array] cmd The command to run (String or Array of arguments)
77
77
  # @param [String] stdin The +stdin+ to provide to the command
78
+ # @param [Array] opts List of bash options, like "--login" and "--noprofile"
78
79
  # @param [Hash] env Hash of environment variables
79
80
  # @param [Loog|IO] log Logging facility with +.debug()+ method (or +$stdout+, or nil if should go to +/dev/null+)
80
81
  # @param [Array] accept List of accepted exit codes (accepts all if the list is +nil+)
81
82
  # @param [Boolean] both If set to TRUE, the function returns an array +(stdout, code)+
82
83
  # @param [Integer] level Logging level (use +Logger::DEBUG+, +Logger::INFO+, +Logger::WARN+, or +Logger::ERROR+)
83
84
  # @return [String] Everything that was printed to the +stdout+ by the command
84
- def qbash(cmd, stdin: '', env: {}, log: Loog::NULL, accept: [0], both: false, level: Logger::DEBUG)
85
+ def qbash(cmd, opts: [], stdin: '', env: {}, log: Loog::NULL, accept: [0], both: false, level: Logger::DEBUG)
85
86
  env.each { |k, v| raise "env[#{k}] is nil" if v.nil? }
86
87
  cmd = cmd.reject { |a| a.nil? || (a.is_a?(String) && a.empty?) }.join(' ') if cmd.is_a?(Array)
87
88
  logit =
88
89
  lambda do |msg|
90
+ msg = msg.gsub(/\n$/, '')
89
91
  mtd =
90
92
  case level
91
93
  when Logger::DEBUG
@@ -104,19 +106,21 @@ module Kernel
104
106
  elsif log.respond_to?(mtd)
105
107
  log.__send__(mtd, msg)
106
108
  else
107
- log.print(msg)
109
+ log.print("#{msg}\n")
108
110
  end
109
111
  end
110
- logit["+ #{cmd}"]
111
112
  buf = ''
112
113
  e = 1
113
114
  start = Time.now
114
- Open3.popen2e(env, "/bin/bash -c #{Shellwords.escape(cmd)}") do |sin, sout, ctrl|
115
+ bash = ['exec', '/bin/bash'] + opts + ['-c', Shellwords.escape(cmd)]
116
+ Open3.popen2e(env, bash.join(' ')) do |sin, sout, ctrl|
117
+ pid = ctrl.pid
118
+ logit["+ #{cmd} /##{pid}"]
115
119
  consume =
116
120
  lambda do
117
121
  loop do
118
122
  break if sout.eof?
119
- ln = sout.gets
123
+ ln = sout.gets # together with the \n at the end
120
124
  next if ln.nil?
121
125
  next if ln.empty?
122
126
  buf += ln
@@ -132,22 +136,24 @@ module Kernel
132
136
  if block_given?
133
137
  watch = Thread.new { consume.call }
134
138
  watch.abort_on_exception = true
135
- pid = ctrl.pid
136
- yield pid
137
- sout.close
138
- watch.join(0.01)
139
- watch.kill if watch.alive?
140
- attempt = 1
141
- since = Time.now
142
- loop do
143
- Process.kill(0, pid) # should be dead already (raising Errno::ESRCH)
144
- Process.kill('TERM', pid) # let's try to kill it
145
- logit["Tried to stop ##{pid} with SIGTERM (attempt no.#{attempt}, #{since.ago}): #{cmd}"]
146
- sleep(0.1)
147
- attempt += 1
148
- rescue Errno::ESRCH
149
- logit["Process ##{pid} gracefully reacted to SIGTERM"] if attempt > 1
150
- break
139
+ begin
140
+ yield pid
141
+ ensure
142
+ sout.close
143
+ watch.join(0.01)
144
+ watch.kill if watch.alive?
145
+ attempt = 1
146
+ since = Time.now
147
+ loop do
148
+ Process.kill(0, pid) # should be dead already (raising Errno::ESRCH)
149
+ Process.kill('TERM', pid) # let's try to kill it
150
+ logit["Tried to stop ##{pid} with SIGTERM (attempt no.#{attempt}, #{since.ago}): #{cmd}"]
151
+ sleep(0.1)
152
+ attempt += 1
153
+ rescue Errno::ESRCH
154
+ logit["Process ##{pid} reacted to SIGTERM, after #{attempt} attempts and #{since.ago}"] if attempt > 1
155
+ break
156
+ end
151
157
  end
152
158
  else
153
159
  consume.call
data/qbash.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
9
9
  s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
10
10
  s.required_ruby_version = '>=3.2'
11
11
  s.name = 'qbash'
12
- s.version = '0.4.4'
12
+ s.version = '0.4.5'
13
13
  s.license = 'MIT'
14
14
  s.summary = 'Quick Executor of a BASH Command'
15
15
  s.description =
data/test/test_qbash.rb CHANGED
@@ -79,6 +79,14 @@ class TestQbash < Minitest::Test
79
79
  end
80
80
  end
81
81
 
82
+ def test_lets_exception_float_up
83
+ assert_raises(StandardError) do
84
+ qbash('sleep 767676', accept: nil, log: $stdout) do
85
+ raise 'intentional'
86
+ end
87
+ end
88
+ end
89
+
82
90
  def test_kills_in_thread
83
91
  Thread.new do
84
92
  qbash('sleep 9999', accept: nil) do |pid|
@@ -87,6 +95,21 @@ class TestQbash < Minitest::Test
87
95
  end.join
88
96
  end
89
97
 
98
+ def test_truly_kills
99
+ qbash('sleep 9876543', accept: nil) do
100
+ sleep(0.1)
101
+ end
102
+ refute_empty(qbash('ps ax | grep -v 9876543'))
103
+ end
104
+
105
+ def test_executes_without_sh_only_bash
106
+ qbash('sleep 89898989', accept: nil) do
107
+ refute_empty(qbash('ps ax | grep -v "sh -c exec /bin/bash -c sleep 89898989" | grep -v grep'))
108
+ refute_empty(qbash('ps ax | grep "sleep 89898989" | grep -v grep'))
109
+ sleep(0.1)
110
+ end
111
+ end
112
+
90
113
  def test_logs_in_background
91
114
  stdout = nil
92
115
  buf = Loog::Buffer.new
@@ -114,7 +137,17 @@ class TestQbash < Minitest::Test
114
137
  sleep(0.1)
115
138
  pid = i
116
139
  end
117
- assert_equal(buf.to_s, "+ echo one; echo two\n##{pid}: one\n##{pid}: two\n")
140
+ assert_equal(buf.to_s, "+ echo one; echo two /##{pid}\n##{pid}: one\n##{pid}: two\n")
141
+ end
142
+
143
+ def test_logs_multi_line_to_console
144
+ console = FakeConsole.new
145
+ pid = nil
146
+ qbash('echo one; echo two', log: console, accept: nil) do |i|
147
+ sleep(0.1)
148
+ pid = i
149
+ end
150
+ assert_equal(console.to_s, "+ echo one; echo two /##{pid}\n##{pid}: one\n##{pid}: two\n")
118
151
  end
119
152
 
120
153
  def test_with_both
@@ -141,4 +174,18 @@ class TestQbash < Minitest::Test
141
174
  refute(t.join(0.1))
142
175
  t.kill
143
176
  end
177
+
178
+ class FakeConsole
179
+ def initialize
180
+ @buf = ''
181
+ end
182
+
183
+ def to_s
184
+ @buf
185
+ end
186
+
187
+ def print(ln)
188
+ @buf += ln
189
+ end
190
+ end
144
191
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qbash
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko