qbash 0.6.0 → 0.7.0
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/Gemfile.lock +8 -6
- data/README.md +14 -4
- data/lib/qbash.rb +61 -42
- data/qbash.gemspec +1 -1
- 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: d9269eaeacc7fe858cd6e08abbcb5b66ed09b3f4bf06bbca5ea976e19cc2f125
|
|
4
|
+
data.tar.gz: bb0ce33d753a822af98417da51d716a5726f29df839da3c7b17bb51bdf37c9e4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3cee929894765836118f8bdbd5a505a0259586d15c5337d804806dbae2f994aa8f2f184d49e9e0d67edc42dea6d2c4b255e14a28276339f619f1635292e4b27f
|
|
7
|
+
data.tar.gz: e1241fe9604fd13a4c8352a56b408be3fe442c5518d13280496ca2f002e1b66579ba31911db8452a46b673dfb8b3a55a0e7911b24486c4e1b29ab9e4b6fdc07f
|
data/Gemfile.lock
CHANGED
|
@@ -38,13 +38,13 @@ GEM
|
|
|
38
38
|
cucumber-gherkin (> 36, < 40)
|
|
39
39
|
cucumber-messages (> 31, < 33)
|
|
40
40
|
cucumber-tag-expressions (> 6, < 9)
|
|
41
|
-
cucumber-cucumber-expressions (
|
|
41
|
+
cucumber-cucumber-expressions (19.0.0)
|
|
42
42
|
bigdecimal
|
|
43
|
-
cucumber-gherkin (
|
|
44
|
-
cucumber-messages (>= 31, <
|
|
43
|
+
cucumber-gherkin (38.0.0)
|
|
44
|
+
cucumber-messages (>= 31, < 33)
|
|
45
45
|
cucumber-html-formatter (22.3.0)
|
|
46
46
|
cucumber-messages (> 23, < 33)
|
|
47
|
-
cucumber-messages (
|
|
47
|
+
cucumber-messages (32.0.1)
|
|
48
48
|
cucumber-tag-expressions (8.1.0)
|
|
49
49
|
date (3.5.1)
|
|
50
50
|
diff-lcs (1.6.2)
|
|
@@ -52,6 +52,7 @@ GEM
|
|
|
52
52
|
elapsed (0.2.2)
|
|
53
53
|
loog (~> 0.6)
|
|
54
54
|
tago (~> 0.1)
|
|
55
|
+
ellipsized (0.3.0)
|
|
55
56
|
erb (6.0.1)
|
|
56
57
|
ffi (1.17.3-aarch64-linux-gnu)
|
|
57
58
|
ffi (1.17.3-arm-linux-gnu)
|
|
@@ -65,7 +66,8 @@ GEM
|
|
|
65
66
|
language_server-protocol (3.17.0.5)
|
|
66
67
|
lint_roller (1.1.0)
|
|
67
68
|
logger (1.7.0)
|
|
68
|
-
loog (0.
|
|
69
|
+
loog (0.7.2)
|
|
70
|
+
ellipsized
|
|
69
71
|
logger (~> 1.0)
|
|
70
72
|
memoist3 (1.0.0)
|
|
71
73
|
mini_mime (1.1.5)
|
|
@@ -153,7 +155,7 @@ GEM
|
|
|
153
155
|
sys-uname (1.4.1)
|
|
154
156
|
ffi (~> 1.1)
|
|
155
157
|
memoist3 (~> 1.0.0)
|
|
156
|
-
tago (0.
|
|
158
|
+
tago (0.7.0)
|
|
157
159
|
tsort (0.2.0)
|
|
158
160
|
unicode-display_width (3.2.0)
|
|
159
161
|
unicode-emoji (~> 4.1)
|
data/README.md
CHANGED
|
@@ -28,13 +28,23 @@ Then, you can use [qbash] global function:
|
|
|
28
28
|
|
|
29
29
|
```ruby
|
|
30
30
|
require 'qbash'
|
|
31
|
-
stdout = qbash('echo "Hello, world!"'
|
|
31
|
+
stdout = qbash('echo "Hello, world!"')
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
If the command fails, an exception is raised.
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
By default, `stderr` merges with the `stdout` logger.
|
|
37
|
+
You can redirect it elsewhere:
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
# Redirect stderr to a separate logger
|
|
41
|
+
out = Loog::Buffer.new
|
|
42
|
+
err = Loog::Buffer.new
|
|
43
|
+
qbash('cmd', stdout: out, stderr: err)
|
|
44
|
+
|
|
45
|
+
# Discard stderr completely
|
|
46
|
+
qbash('cmd', stderr: nil)
|
|
47
|
+
```
|
|
38
48
|
|
|
39
49
|
It's possible to provide the standard input and environment variables:
|
|
40
50
|
|
|
@@ -48,7 +58,7 @@ It's possible to configure the logging facility too, for example,
|
|
|
48
58
|
|
|
49
59
|
```ruby
|
|
50
60
|
require 'loog'
|
|
51
|
-
qbash('echo "Hello, world!"',
|
|
61
|
+
qbash('echo "Hello, world!"', stdout: Loog::VERBOSE)
|
|
52
62
|
```
|
|
53
63
|
|
|
54
64
|
You can also make it return both stdout and exit code,
|
data/lib/qbash.rb
CHANGED
|
@@ -51,12 +51,12 @@ module Kernel
|
|
|
51
51
|
#
|
|
52
52
|
# == Logging
|
|
53
53
|
#
|
|
54
|
-
# # Enable detailed logging to
|
|
55
|
-
# qbash('ls -la',
|
|
54
|
+
# # Enable detailed logging to console
|
|
55
|
+
# qbash('ls -la', stdout: $stdout)
|
|
56
56
|
#
|
|
57
57
|
# # Use custom logger with specific level
|
|
58
58
|
# logger = Logger.new($stdout)
|
|
59
|
-
# qbash('make all',
|
|
59
|
+
# qbash('make all', stdout: logger, level: Logger::INFO)
|
|
60
60
|
#
|
|
61
61
|
# == Process Control
|
|
62
62
|
#
|
|
@@ -76,7 +76,21 @@ module Kernel
|
|
|
76
76
|
# qbash('git status', chdir: '/path/to/repo')
|
|
77
77
|
#
|
|
78
78
|
# For command with multiple arguments, you can use +Shellwords.escape()+ to
|
|
79
|
-
# properly escape each argument.
|
|
79
|
+
# properly escape each argument.
|
|
80
|
+
#
|
|
81
|
+
# == Stderr Handling
|
|
82
|
+
#
|
|
83
|
+
# By default, stderr merges with stdout. You can redirect it elsewhere:
|
|
84
|
+
#
|
|
85
|
+
# # Merge stderr with stdout (default)
|
|
86
|
+
# output = qbash('cmd', stderr: :stdout)
|
|
87
|
+
#
|
|
88
|
+
# # Redirect stderr to a separate logger
|
|
89
|
+
# err_log = Loog::Buffer.new
|
|
90
|
+
# output = qbash('cmd', stderr: err_log)
|
|
91
|
+
#
|
|
92
|
+
# # Discard stderr completely
|
|
93
|
+
# output = qbash('cmd', stderr: nil)
|
|
80
94
|
#
|
|
81
95
|
# Read this <a href="https://github.com/yegor256/qbash">README</a> file for more details.
|
|
82
96
|
#
|
|
@@ -84,90 +98,95 @@ module Kernel
|
|
|
84
98
|
# @param [String] stdin The +stdin+ to provide to the command
|
|
85
99
|
# @param [Array] opts List of bash options, like "--login" and "--noprofile"
|
|
86
100
|
# @param [Hash] env Hash of environment variables
|
|
87
|
-
# @param [Loog|IO]
|
|
101
|
+
# @param [Loog|IO] stdout Logging facility with +.debug()+ method (or +$stdout+, or nil if should go to +/dev/null+)
|
|
102
|
+
# @param [Loog|IO] stderr Where to send stderr
|
|
88
103
|
# @param [Array] accept List of accepted exit codes (accepts all if the list is +nil+)
|
|
89
104
|
# @param [Boolean] both If set to TRUE, the function returns an array +(stdout, code)+
|
|
90
105
|
# @param [Integer] level Logging level (use +Logger::DEBUG+, +Logger::INFO+, +Logger::WARN+, or +Logger::ERROR+)
|
|
91
106
|
# @param [String] chdir Directory to change to before running the command (or +nil+ to use current directory)
|
|
92
107
|
# @return [String] Everything that was printed to the +stdout+ by the command
|
|
93
|
-
def qbash(*cmd, opts: [], stdin: '', env: {},
|
|
94
|
-
chdir: nil)
|
|
108
|
+
def qbash(*cmd, opts: [], stdin: '', env: {}, stdout: Loog::NULL, stderr: nil, accept: [0], both: false,
|
|
109
|
+
level: Logger::DEBUG, chdir: nil)
|
|
110
|
+
stderr ||= stdout
|
|
95
111
|
env.each { |k, v| raise "env[#{k}] is nil" if v.nil? }
|
|
96
112
|
cmd = cmd.reject { |a| a.nil? || (a.is_a?(String) && a.empty?) }.join(' ')
|
|
97
|
-
|
|
98
|
-
|
|
113
|
+
mtd =
|
|
114
|
+
case level
|
|
115
|
+
when Logger::DEBUG
|
|
116
|
+
:debug
|
|
117
|
+
when Logger::INFO
|
|
118
|
+
:info
|
|
119
|
+
when Logger::WARN
|
|
120
|
+
:warn
|
|
121
|
+
when Logger::ERROR
|
|
122
|
+
:error
|
|
123
|
+
else
|
|
124
|
+
raise "Unknown log level #{level}"
|
|
125
|
+
end
|
|
126
|
+
printer =
|
|
127
|
+
lambda do |target, msg|
|
|
99
128
|
msg = msg.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?').gsub(/\n$/, '')
|
|
100
|
-
|
|
101
|
-
case level
|
|
102
|
-
when Logger::DEBUG
|
|
103
|
-
:debug
|
|
104
|
-
when Logger::INFO
|
|
105
|
-
:info
|
|
106
|
-
when Logger::WARN
|
|
107
|
-
:warn
|
|
108
|
-
when Logger::ERROR
|
|
109
|
-
:error
|
|
110
|
-
else
|
|
111
|
-
raise "Unknown log level #{level}"
|
|
112
|
-
end
|
|
113
|
-
if log.nil?
|
|
129
|
+
if target.nil?
|
|
114
130
|
# nothing to print
|
|
115
|
-
elsif
|
|
116
|
-
|
|
131
|
+
elsif target.respond_to?(mtd)
|
|
132
|
+
target.__send__(mtd, msg)
|
|
117
133
|
else
|
|
118
|
-
|
|
134
|
+
target.print("#{msg}\n")
|
|
119
135
|
end
|
|
120
136
|
end
|
|
121
|
-
buf = ''
|
|
137
|
+
buf = +''
|
|
122
138
|
e = 1
|
|
123
139
|
start = Time.now
|
|
124
140
|
bash = ['/bin/bash'] + opts + ['-c', cmd]
|
|
125
141
|
popen = chdir.nil? ? [env, *bash] : [env, *bash, { chdir: }]
|
|
126
|
-
Open3.
|
|
142
|
+
Open3.send(:popen3, *popen) do |sin, sout, serr, ctrl|
|
|
127
143
|
pid = ctrl.pid
|
|
128
|
-
|
|
144
|
+
printer[stderr, "+ #{cmd} /##{pid}"]
|
|
129
145
|
consume =
|
|
130
|
-
lambda do
|
|
146
|
+
lambda do |stream, target, buffer|
|
|
131
147
|
loop do
|
|
132
148
|
sleep 0.001
|
|
133
|
-
break if
|
|
134
|
-
ln =
|
|
149
|
+
break if stream.closed? || stream.eof?
|
|
150
|
+
ln = stream.gets
|
|
135
151
|
next if ln.nil?
|
|
136
152
|
next if ln.empty?
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
logit[ln]
|
|
153
|
+
buffer << ln if buffer
|
|
154
|
+
printer[target, "##{pid}: #{ln}"]
|
|
140
155
|
rescue IOError => e
|
|
141
|
-
|
|
156
|
+
printer[stderr, e.message]
|
|
142
157
|
break
|
|
143
158
|
end
|
|
144
159
|
end
|
|
145
160
|
sin.write(stdin)
|
|
146
161
|
sin.close
|
|
147
162
|
if block_given?
|
|
148
|
-
watch = Thread.new { consume.call }
|
|
163
|
+
watch = Thread.new { consume.call(sout, stdout, buf) }
|
|
149
164
|
watch.abort_on_exception = true
|
|
150
165
|
begin
|
|
151
166
|
yield pid
|
|
152
167
|
ensure
|
|
153
168
|
sout.close
|
|
169
|
+
serr&.close
|
|
154
170
|
watch.join(0.01)
|
|
155
171
|
watch.kill if watch.alive?
|
|
156
172
|
attempt = 1
|
|
157
173
|
since = Time.now
|
|
158
174
|
loop do
|
|
159
|
-
Process.kill(0, pid)
|
|
160
|
-
Process.kill('TERM', pid)
|
|
161
|
-
|
|
175
|
+
Process.kill(0, pid)
|
|
176
|
+
Process.kill('TERM', pid)
|
|
177
|
+
printer[stderr, "Tried to stop ##{pid} with SIGTERM (attempt no.#{attempt}, #{since.ago}): #{cmd}"]
|
|
162
178
|
sleep(0.1)
|
|
163
179
|
attempt += 1
|
|
164
180
|
rescue Errno::ESRCH
|
|
165
|
-
|
|
181
|
+
if attempt > 1
|
|
182
|
+
printer[stderr,
|
|
183
|
+
"Process ##{pid} reacted to SIGTERM, after #{attempt} attempts and #{since.ago}"]
|
|
184
|
+
end
|
|
166
185
|
break
|
|
167
186
|
end
|
|
168
187
|
end
|
|
169
188
|
else
|
|
170
|
-
consume.call
|
|
189
|
+
consume.call(sout, stdout, buf)
|
|
171
190
|
end
|
|
172
191
|
e = ctrl.value.exitstatus
|
|
173
192
|
if !accept.nil? && !accept.include?(e)
|
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.
|
|
12
|
+
s.version = '0.7.0'
|
|
13
13
|
s.license = 'MIT'
|
|
14
14
|
s.summary = 'Quick Executor of a BASH Command'
|
|
15
15
|
s.description =
|