qbash 0.4.1 → 0.4.3
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +8 -0
- data/lib/qbash.rb +58 -65
- data/qbash.gemspec +1 -1
- data/test/test__helper.rb +2 -2
- data/test/test_qbash.rb +20 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df6e6d3493e78bba7aa90acd7e51c84b8b869e5fac3e1fe696ed67e29a50219c
|
4
|
+
data.tar.gz: 7b5b9e9ae374085166d01b17ddf16c7ba740b50f5f0c4dfb407bb9da2ffcc6bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 348fabb99cb7a962b51d354b0b668e08e009f9c82db7433c91fa738336e19f0e51c9cd319d0dae522a73813e7a80344a54e717cca09d9f67ad1068e403058966
|
7
|
+
data.tar.gz: 3c72c3b7a39d5e3523cda49ed38be201147e07d15f8cae5b69bfd74b5f2cec6b8a8ac3f4d7d78ffc321a415893ed1c46005372030aa651a15679d8686523eac3
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -12,6 +12,7 @@ gem 'minitest-reporters', '~>1.7', require: false
|
|
12
12
|
gem 'net-ping', '~>2.0', require: false
|
13
13
|
gem 'rake', '~>13.2', require: false
|
14
14
|
gem 'random-port', '~>0.0', require: false
|
15
|
+
gem 'rdoc', '~>6.13', require: false
|
15
16
|
gem 'rubocop', '~>1.73', require: false
|
16
17
|
gem 'rubocop-minitest', '>0', require: false
|
17
18
|
gem 'rubocop-performance', '>0', require: false
|
data/Gemfile.lock
CHANGED
@@ -45,6 +45,7 @@ GEM
|
|
45
45
|
cucumber-messages (> 19, < 28)
|
46
46
|
cucumber-messages (22.0.0)
|
47
47
|
cucumber-tag-expressions (6.1.2)
|
48
|
+
date (3.4.1)
|
48
49
|
diff-lcs (1.6.1)
|
49
50
|
docile (1.4.1)
|
50
51
|
elapsed (0.0.1)
|
@@ -94,12 +95,17 @@ GEM
|
|
94
95
|
ast (~> 2.4.1)
|
95
96
|
racc
|
96
97
|
prism (1.4.0)
|
98
|
+
psych (5.2.5)
|
99
|
+
date
|
100
|
+
stringio
|
97
101
|
public_suffix (6.0.2)
|
98
102
|
racc (1.8.1)
|
99
103
|
rainbow (3.1.1)
|
100
104
|
rake (13.2.1)
|
101
105
|
random-port (0.7.5)
|
102
106
|
tago (> 0)
|
107
|
+
rdoc (6.13.1)
|
108
|
+
psych (>= 4.0.0)
|
103
109
|
regexp_parser (2.10.0)
|
104
110
|
rexml (3.4.1)
|
105
111
|
rubocop (1.75.5)
|
@@ -137,6 +143,7 @@ GEM
|
|
137
143
|
simplecov (~> 0.19)
|
138
144
|
simplecov-html (0.13.1)
|
139
145
|
simplecov_json_formatter (0.1.4)
|
146
|
+
stringio (3.1.7)
|
140
147
|
sys-uname (1.3.1)
|
141
148
|
ffi (~> 1.1)
|
142
149
|
tago (0.1.0)
|
@@ -171,6 +178,7 @@ DEPENDENCIES
|
|
171
178
|
qbash!
|
172
179
|
rake (~> 13.2)
|
173
180
|
random-port (~> 0.0)
|
181
|
+
rdoc (~> 6.13)
|
174
182
|
rubocop (~> 1.73)
|
175
183
|
rubocop-minitest (> 0)
|
176
184
|
rubocop-performance (> 0)
|
data/lib/qbash.rb
CHANGED
@@ -84,84 +84,77 @@ module Kernel
|
|
84
84
|
def qbash(cmd, stdin: '', env: {}, log: Loog::NULL, accept: [0], both: false, level: Logger::DEBUG)
|
85
85
|
env.each { |k, v| raise "env[#{k}] is nil" if v.nil? }
|
86
86
|
cmd = cmd.reject { |a| a.nil? || (a.is_a?(String) && a.empty?) }.join(' ') if cmd.is_a?(Array)
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
87
|
+
logit =
|
88
|
+
lambda do |msg|
|
89
|
+
mtd =
|
90
|
+
case level
|
91
|
+
when Logger::DEBUG
|
92
|
+
:debug
|
93
|
+
when Logger::INFO
|
94
|
+
:info
|
95
|
+
when Logger::WARN
|
96
|
+
:warn
|
97
|
+
when Logger::ERROR
|
98
|
+
:error
|
99
|
+
else
|
100
|
+
raise "Unknown log level #{level}"
|
101
|
+
end
|
102
|
+
if log.nil?
|
103
|
+
# nothing to print
|
104
|
+
elsif log.respond_to?(mtd)
|
105
|
+
log.__send__(mtd, msg)
|
106
|
+
else
|
107
|
+
log.print("#{msg}\n")
|
108
|
+
end
|
99
109
|
end
|
100
|
-
|
101
|
-
# nothing to print
|
102
|
-
elsif log.respond_to?(mtd)
|
103
|
-
log.__send__(mtd, "+ #{cmd}")
|
104
|
-
else
|
105
|
-
log.print("+ #{cmd}\n")
|
106
|
-
end
|
110
|
+
logit["+ #{cmd}"]
|
107
111
|
buf = ''
|
108
112
|
e = 1
|
109
113
|
start = Time.now
|
110
114
|
Open3.popen2e(env, "/bin/bash -c #{Shellwords.escape(cmd)}") do |sin, sout, ctrl|
|
115
|
+
consume =
|
116
|
+
lambda do
|
117
|
+
loop do
|
118
|
+
break if sout.eof?
|
119
|
+
ln = sout.gets
|
120
|
+
next if ln.nil?
|
121
|
+
next if ln.empty?
|
122
|
+
buf += ln
|
123
|
+
ln = "##{ctrl.pid}: #{ln}"
|
124
|
+
logit[ln]
|
125
|
+
rescue IOError => e
|
126
|
+
logit[e.message]
|
127
|
+
break
|
128
|
+
end
|
129
|
+
end
|
111
130
|
sin.write(stdin)
|
112
131
|
sin.close
|
113
132
|
if block_given?
|
114
|
-
|
115
|
-
watch =
|
116
|
-
Thread.new do
|
117
|
-
until closed
|
118
|
-
begin
|
119
|
-
ln = sout.gets
|
120
|
-
rescue IOError => e
|
121
|
-
ln = Backtrace.new(e).to_s
|
122
|
-
end
|
123
|
-
next if ln.nil?
|
124
|
-
next if ln.empty?
|
125
|
-
ln = "##{ctrl.pid}: #{ln}"
|
126
|
-
if log.nil?
|
127
|
-
# no logging
|
128
|
-
elsif log.respond_to?(mtd)
|
129
|
-
log.__send__(mtd, ln)
|
130
|
-
else
|
131
|
-
log.print(ln)
|
132
|
-
end
|
133
|
-
buf += ln
|
134
|
-
end
|
135
|
-
end
|
133
|
+
watch = Thread.new { consume.call }
|
134
|
+
watch.abort_on_exception = true
|
136
135
|
pid = ctrl.pid
|
137
136
|
yield pid
|
138
|
-
|
139
|
-
|
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
|
140
148
|
rescue Errno::ESRCH
|
141
|
-
|
149
|
+
logit["Process ##{pid} exited gracefully"]
|
150
|
+
break
|
142
151
|
end
|
143
|
-
closed = true
|
144
|
-
watch.join
|
145
152
|
else
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
end
|
152
|
-
if log.nil?
|
153
|
-
# no logging
|
154
|
-
elsif log.respond_to?(mtd)
|
155
|
-
log.__send__(mtd, ln)
|
156
|
-
else
|
157
|
-
log.print(ln)
|
158
|
-
end
|
159
|
-
buf += ln
|
160
|
-
end
|
161
|
-
e = ctrl.value.to_i
|
162
|
-
if !accept.nil? && !accept.include?(e)
|
163
|
-
raise "The command '#{cmd}' failed with exit code ##{e} in #{start.ago}\n#{buf}"
|
164
|
-
end
|
153
|
+
consume.call
|
154
|
+
end
|
155
|
+
e = ctrl.value.to_i
|
156
|
+
if !accept.nil? && !accept.include?(e)
|
157
|
+
raise "The command '#{cmd}' failed with exit code ##{e} in #{start.ago}\n#{buf}"
|
165
158
|
end
|
166
159
|
end
|
167
160
|
return [buf, e] if both
|
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.
|
12
|
+
s.version = '0.4.3'
|
13
13
|
s.license = 'MIT'
|
14
14
|
s.summary = 'Quick Executor of a BASH Command'
|
15
15
|
s.description =
|
data/test/test__helper.rb
CHANGED
@@ -15,8 +15,8 @@ unless SimpleCov.running || ENV['PICKS']
|
|
15
15
|
SimpleCov::Formatter::CoberturaFormatter
|
16
16
|
]
|
17
17
|
)
|
18
|
-
SimpleCov.minimum_coverage
|
19
|
-
SimpleCov.minimum_coverage_by_file
|
18
|
+
SimpleCov.minimum_coverage 95
|
19
|
+
SimpleCov.minimum_coverage_by_file 95
|
20
20
|
SimpleCov.start do
|
21
21
|
add_filter 'test/'
|
22
22
|
add_filter 'vendor/'
|
data/test/test_qbash.rb
CHANGED
@@ -81,7 +81,7 @@ class TestQbash < Minitest::Test
|
|
81
81
|
|
82
82
|
def test_kills_in_thread
|
83
83
|
Thread.new do
|
84
|
-
qbash('sleep 9999') do |pid|
|
84
|
+
qbash('sleep 9999', accept: nil) do |pid|
|
85
85
|
Process.kill('KILL', pid)
|
86
86
|
end
|
87
87
|
end.join
|
@@ -92,9 +92,10 @@ class TestQbash < Minitest::Test
|
|
92
92
|
buf = Loog::Buffer.new
|
93
93
|
Dir.mktmpdir do |home|
|
94
94
|
flag = File.join(home, 'started.txt')
|
95
|
+
cmd = "while true; do date; touch #{Shellwords.escape(flag)}; sleep 0.001; done"
|
95
96
|
Thread.new do
|
96
97
|
stdout =
|
97
|
-
qbash(
|
98
|
+
qbash(cmd, log: buf, accept: nil) do |pid|
|
98
99
|
loop { break if File.exist?(flag) }
|
99
100
|
Process.kill('KILL', pid)
|
100
101
|
end
|
@@ -113,4 +114,21 @@ class TestQbash < Minitest::Test
|
|
113
114
|
refute_empty(stdout)
|
114
115
|
end
|
115
116
|
end
|
117
|
+
|
118
|
+
def test_exists_after_background_stop
|
119
|
+
stop = false
|
120
|
+
pid = nil
|
121
|
+
t =
|
122
|
+
Thread.new do
|
123
|
+
qbash('trap "" TERM; sleep 10', accept: nil) do |id|
|
124
|
+
pid = id
|
125
|
+
loop { break if stop }
|
126
|
+
end
|
127
|
+
end
|
128
|
+
t.abort_on_exception = true
|
129
|
+
sleep(0.01)
|
130
|
+
stop = true
|
131
|
+
refute(t.join(0.1))
|
132
|
+
t.kill
|
133
|
+
end
|
116
134
|
end
|