qbash 0.5.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 +40 -38
- data/README.md +14 -4
- data/lib/qbash.rb +71 -41
- 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
|
@@ -10,13 +10,13 @@ PATH
|
|
|
10
10
|
GEM
|
|
11
11
|
remote: https://rubygems.org/
|
|
12
12
|
specs:
|
|
13
|
-
addressable (2.8.
|
|
14
|
-
public_suffix (>= 2.0.2, <
|
|
13
|
+
addressable (2.8.8)
|
|
14
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
15
15
|
ansi (1.5.0)
|
|
16
16
|
ast (2.4.3)
|
|
17
17
|
backtrace (0.4.1)
|
|
18
18
|
base64 (0.3.0)
|
|
19
|
-
bigdecimal (
|
|
19
|
+
bigdecimal (4.0.1)
|
|
20
20
|
builder (3.3.0)
|
|
21
21
|
crack (1.0.1)
|
|
22
22
|
bigdecimal
|
|
@@ -33,39 +33,41 @@ GEM
|
|
|
33
33
|
mini_mime (~> 1.1)
|
|
34
34
|
multi_test (~> 1.1)
|
|
35
35
|
sys-uname (~> 1.3)
|
|
36
|
-
cucumber-ci-environment (
|
|
37
|
-
cucumber-core (
|
|
38
|
-
cucumber-gherkin (>
|
|
39
|
-
cucumber-messages (>
|
|
40
|
-
cucumber-tag-expressions (>
|
|
41
|
-
cucumber-cucumber-expressions (
|
|
36
|
+
cucumber-ci-environment (11.0.0)
|
|
37
|
+
cucumber-core (16.1.1)
|
|
38
|
+
cucumber-gherkin (> 36, < 40)
|
|
39
|
+
cucumber-messages (> 31, < 33)
|
|
40
|
+
cucumber-tag-expressions (> 6, < 9)
|
|
41
|
+
cucumber-cucumber-expressions (19.0.0)
|
|
42
42
|
bigdecimal
|
|
43
|
-
cucumber-gherkin (
|
|
44
|
-
cucumber-messages (
|
|
45
|
-
cucumber-html-formatter (
|
|
46
|
-
cucumber-messages (>
|
|
47
|
-
cucumber-messages (
|
|
43
|
+
cucumber-gherkin (38.0.0)
|
|
44
|
+
cucumber-messages (>= 31, < 33)
|
|
45
|
+
cucumber-html-formatter (22.3.0)
|
|
46
|
+
cucumber-messages (> 23, < 33)
|
|
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)
|
|
51
51
|
docile (1.4.1)
|
|
52
|
-
elapsed (0.2.
|
|
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
|
-
ffi (1.17.
|
|
57
|
-
ffi (1.17.
|
|
58
|
-
ffi (1.17.
|
|
59
|
-
ffi (1.17.
|
|
60
|
-
ffi (1.17.
|
|
61
|
-
ffi (1.17.
|
|
62
|
-
ffi (1.17.
|
|
57
|
+
ffi (1.17.3-aarch64-linux-gnu)
|
|
58
|
+
ffi (1.17.3-arm-linux-gnu)
|
|
59
|
+
ffi (1.17.3-arm64-darwin)
|
|
60
|
+
ffi (1.17.3-x64-mingw-ucrt)
|
|
61
|
+
ffi (1.17.3-x86-linux-gnu)
|
|
62
|
+
ffi (1.17.3-x86_64-darwin)
|
|
63
|
+
ffi (1.17.3-x86_64-linux-gnu)
|
|
63
64
|
hashdiff (1.2.1)
|
|
64
65
|
json (2.18.0)
|
|
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)
|
|
@@ -79,36 +81,36 @@ GEM
|
|
|
79
81
|
ruby-progressbar
|
|
80
82
|
multi_test (1.1.0)
|
|
81
83
|
net-ping (2.0.8)
|
|
82
|
-
nokogiri (1.
|
|
84
|
+
nokogiri (1.19.0)
|
|
83
85
|
mini_portile2 (~> 2.8.2)
|
|
84
86
|
racc (~> 1.4)
|
|
85
|
-
nokogiri (1.
|
|
87
|
+
nokogiri (1.19.0-aarch64-linux-gnu)
|
|
86
88
|
racc (~> 1.4)
|
|
87
|
-
nokogiri (1.
|
|
89
|
+
nokogiri (1.19.0-arm-linux-gnu)
|
|
88
90
|
racc (~> 1.4)
|
|
89
|
-
nokogiri (1.
|
|
91
|
+
nokogiri (1.19.0-arm64-darwin)
|
|
90
92
|
racc (~> 1.4)
|
|
91
|
-
nokogiri (1.
|
|
93
|
+
nokogiri (1.19.0-x64-mingw-ucrt)
|
|
92
94
|
racc (~> 1.4)
|
|
93
|
-
nokogiri (1.
|
|
95
|
+
nokogiri (1.19.0-x86_64-darwin)
|
|
94
96
|
racc (~> 1.4)
|
|
95
|
-
nokogiri (1.
|
|
97
|
+
nokogiri (1.19.0-x86_64-linux-gnu)
|
|
96
98
|
racc (~> 1.4)
|
|
97
99
|
parallel (1.27.0)
|
|
98
|
-
parser (3.3.10.
|
|
100
|
+
parser (3.3.10.1)
|
|
99
101
|
ast (~> 2.4.1)
|
|
100
102
|
racc
|
|
101
|
-
prism (1.
|
|
103
|
+
prism (1.8.0)
|
|
102
104
|
psych (5.3.1)
|
|
103
105
|
date
|
|
104
106
|
stringio
|
|
105
|
-
public_suffix (
|
|
107
|
+
public_suffix (7.0.2)
|
|
106
108
|
racc (1.8.1)
|
|
107
109
|
rainbow (3.1.1)
|
|
108
110
|
rake (13.3.1)
|
|
109
111
|
random-port (0.7.6)
|
|
110
112
|
tago (~> 0.0)
|
|
111
|
-
rdoc (7.0
|
|
113
|
+
rdoc (7.1.0)
|
|
112
114
|
erb
|
|
113
115
|
psych (>= 4.0.0)
|
|
114
116
|
tsort
|
|
@@ -125,9 +127,9 @@ GEM
|
|
|
125
127
|
rubocop-ast (>= 1.48.0, < 2.0)
|
|
126
128
|
ruby-progressbar (~> 1.7)
|
|
127
129
|
unicode-display_width (>= 2.4.0, < 4.0)
|
|
128
|
-
rubocop-ast (1.
|
|
130
|
+
rubocop-ast (1.49.0)
|
|
129
131
|
parser (>= 3.3.7.2)
|
|
130
|
-
prism (~> 1.
|
|
132
|
+
prism (~> 1.7)
|
|
131
133
|
rubocop-minitest (0.38.2)
|
|
132
134
|
lint_roller (~> 1.1)
|
|
133
135
|
rubocop (>= 1.75.0, < 2.0)
|
|
@@ -153,11 +155,11 @@ 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)
|
|
160
|
-
unicode-emoji (4.
|
|
162
|
+
unicode-emoji (4.2.0)
|
|
161
163
|
w3c_validators (1.3.7)
|
|
162
164
|
json (>= 1.8)
|
|
163
165
|
nokogiri (~> 1.6)
|
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
|
#
|
|
@@ -67,8 +67,30 @@ module Kernel
|
|
|
67
67
|
# # Process will be terminated when block exits
|
|
68
68
|
# end
|
|
69
69
|
#
|
|
70
|
+
# == Changing Working Directory
|
|
71
|
+
#
|
|
72
|
+
# # Execute command in a specific directory
|
|
73
|
+
# files = qbash('ls -la', chdir: '/tmp')
|
|
74
|
+
#
|
|
75
|
+
# # Useful for commands that operate on the current directory
|
|
76
|
+
# qbash('git status', chdir: '/path/to/repo')
|
|
77
|
+
#
|
|
70
78
|
# For command with multiple arguments, you can use +Shellwords.escape()+ to
|
|
71
|
-
# 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)
|
|
72
94
|
#
|
|
73
95
|
# Read this <a href="https://github.com/yegor256/qbash">README</a> file for more details.
|
|
74
96
|
#
|
|
@@ -76,87 +98,95 @@ module Kernel
|
|
|
76
98
|
# @param [String] stdin The +stdin+ to provide to the command
|
|
77
99
|
# @param [Array] opts List of bash options, like "--login" and "--noprofile"
|
|
78
100
|
# @param [Hash] env Hash of environment variables
|
|
79
|
-
# @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
|
|
80
103
|
# @param [Array] accept List of accepted exit codes (accepts all if the list is +nil+)
|
|
81
104
|
# @param [Boolean] both If set to TRUE, the function returns an array +(stdout, code)+
|
|
82
105
|
# @param [Integer] level Logging level (use +Logger::DEBUG+, +Logger::INFO+, +Logger::WARN+, or +Logger::ERROR+)
|
|
106
|
+
# @param [String] chdir Directory to change to before running the command (or +nil+ to use current directory)
|
|
83
107
|
# @return [String] Everything that was printed to the +stdout+ by the command
|
|
84
|
-
def qbash(*cmd, opts: [], stdin: '', env: {},
|
|
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
|
|
85
111
|
env.each { |k, v| raise "env[#{k}] is nil" if v.nil? }
|
|
86
112
|
cmd = cmd.reject { |a| a.nil? || (a.is_a?(String) && a.empty?) }.join(' ')
|
|
87
|
-
|
|
88
|
-
|
|
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|
|
|
89
128
|
msg = msg.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?').gsub(/\n$/, '')
|
|
90
|
-
|
|
91
|
-
case level
|
|
92
|
-
when Logger::DEBUG
|
|
93
|
-
:debug
|
|
94
|
-
when Logger::INFO
|
|
95
|
-
:info
|
|
96
|
-
when Logger::WARN
|
|
97
|
-
:warn
|
|
98
|
-
when Logger::ERROR
|
|
99
|
-
:error
|
|
100
|
-
else
|
|
101
|
-
raise "Unknown log level #{level}"
|
|
102
|
-
end
|
|
103
|
-
if log.nil?
|
|
129
|
+
if target.nil?
|
|
104
130
|
# nothing to print
|
|
105
|
-
elsif
|
|
106
|
-
|
|
131
|
+
elsif target.respond_to?(mtd)
|
|
132
|
+
target.__send__(mtd, msg)
|
|
107
133
|
else
|
|
108
|
-
|
|
134
|
+
target.print("#{msg}\n")
|
|
109
135
|
end
|
|
110
136
|
end
|
|
111
|
-
buf = ''
|
|
137
|
+
buf = +''
|
|
112
138
|
e = 1
|
|
113
139
|
start = Time.now
|
|
114
140
|
bash = ['/bin/bash'] + opts + ['-c', cmd]
|
|
115
|
-
|
|
141
|
+
popen = chdir.nil? ? [env, *bash] : [env, *bash, { chdir: }]
|
|
142
|
+
Open3.send(:popen3, *popen) do |sin, sout, serr, ctrl|
|
|
116
143
|
pid = ctrl.pid
|
|
117
|
-
|
|
144
|
+
printer[stderr, "+ #{cmd} /##{pid}"]
|
|
118
145
|
consume =
|
|
119
|
-
lambda do
|
|
146
|
+
lambda do |stream, target, buffer|
|
|
120
147
|
loop do
|
|
121
148
|
sleep 0.001
|
|
122
|
-
break if
|
|
123
|
-
ln =
|
|
149
|
+
break if stream.closed? || stream.eof?
|
|
150
|
+
ln = stream.gets
|
|
124
151
|
next if ln.nil?
|
|
125
152
|
next if ln.empty?
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
logit[ln]
|
|
153
|
+
buffer << ln if buffer
|
|
154
|
+
printer[target, "##{pid}: #{ln}"]
|
|
129
155
|
rescue IOError => e
|
|
130
|
-
|
|
156
|
+
printer[stderr, e.message]
|
|
131
157
|
break
|
|
132
158
|
end
|
|
133
159
|
end
|
|
134
160
|
sin.write(stdin)
|
|
135
161
|
sin.close
|
|
136
162
|
if block_given?
|
|
137
|
-
watch = Thread.new { consume.call }
|
|
163
|
+
watch = Thread.new { consume.call(sout, stdout, buf) }
|
|
138
164
|
watch.abort_on_exception = true
|
|
139
165
|
begin
|
|
140
166
|
yield pid
|
|
141
167
|
ensure
|
|
142
168
|
sout.close
|
|
169
|
+
serr&.close
|
|
143
170
|
watch.join(0.01)
|
|
144
171
|
watch.kill if watch.alive?
|
|
145
172
|
attempt = 1
|
|
146
173
|
since = Time.now
|
|
147
174
|
loop do
|
|
148
|
-
Process.kill(0, pid)
|
|
149
|
-
Process.kill('TERM', pid)
|
|
150
|
-
|
|
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}"]
|
|
151
178
|
sleep(0.1)
|
|
152
179
|
attempt += 1
|
|
153
180
|
rescue Errno::ESRCH
|
|
154
|
-
|
|
181
|
+
if attempt > 1
|
|
182
|
+
printer[stderr,
|
|
183
|
+
"Process ##{pid} reacted to SIGTERM, after #{attempt} attempts and #{since.ago}"]
|
|
184
|
+
end
|
|
155
185
|
break
|
|
156
186
|
end
|
|
157
187
|
end
|
|
158
188
|
else
|
|
159
|
-
consume.call
|
|
189
|
+
consume.call(sout, stdout, buf)
|
|
160
190
|
end
|
|
161
191
|
e = ctrl.value.exitstatus
|
|
162
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 =
|